2017-01-17 3 views
0

Я хочу вызвать функцию async из цикла do while и выйти, только если функция не возвращает значение. Есть ли способ управлять этим, не имея на самом деле wait вне обратного вызова?Node.js вызывает функцию async изнутри do while loop

Вот код, который, очевидно, всегда выходит в первом контуре, так как функция не перезвонил еще, когда в то время как() оценивается:

var i = 0; 
 
do { 
 
    var foundListing; 
 
    if (i) { 
 
    listing.slug = listing.slug + '-' + (i + 1); 
 
    } 
 
    listingService.getListingBySlug(listing, function(error, pFoundListing) { 
 
    if (error) { 
 
     return callback(util.errorParser(error)); 
 
    } else if (Object.keys(pFoundListing).length) { 
 
     foundListing = pFoundListing; 
 
     i++; 
 
    } 
 
    }); 
 
    //Do I have to wait here??? 
 
} while (foundListing && Object.keys(foundListing).length);

Для Разъяснение: Здесь нужно создать уникальный слизень. Если slug уже существует, я добавляю номер и снова проверяю его, если он существует. Когда я доберусь до числа, которого еще нет, я закончен.

Обновление: Я нашел способ, использующий рекурсию. Я опубликовал рабочий фрагмент как answer.

+0

где - объявление переменной «i» .. –

+0

Вы пытаетесь установить асинхронный вызов в синхронной структуре. В основном код постоянно запускает вызовы 'listingService.getListingBySlug' на каждой итерации цикла, при максимальной скорости javascript может выполнять этот цикл. Вы уверены, что хотите сделать? –

+0

@GiacomoCosimato Это наоборот. Поскольку 'foundListing' пуст в начале,' while() 'part всегда вычисляет false в первом цикле, потому что он установлен в обратном вызове, который еще не был выполнен. В любом случае, это не то, что я хочу. Я хочу только ввести цикл снова, если список был найден в 'listingService.getListingBySlug' – Chry007

ответ

0

Я сделал свою работу, используя рекурсию как предложено Джакомо Cosimato.

Вот фрагмент кода, который работал:

listingController.js

saveListing: function(listing, callback) { 
 
    listingService.findOpenSlug(listing, listing.slug, 1, function(error, listing) { 
 
    if (error) { 
 
     return callback(util.errorParser(error)); 
 
    } else { 
 
     listingService.saveListing(listing, function(error, savedListing) { 
 
     //do some work 
 
     }); 
 
    } 
 
    }); 
 
}

listingService.js

var classMethods = { 
 
    findOpenSlug: function(listing, baseSlug, i, callback) { 
 
    listingRepository.getListingBySlug(listing.slug, function(error, foundListing) { 
 
     if (error) { 
 
     return callback(error); 
 
     } else if (Object.keys(foundListing).length) { 
 
     listing.slug = baseSlug + '-' + (i + 1) 
 
     i++; 
 
     classMethods.findOpenSlug(listing, baseSlug, i, callback); 
 
     } else { 
 
     callback(null, listing); 
 
     } 
 
    }); 
 
    }, 
 
    [...] 
 
}

0

Вы должны использовать обещание в таких случаях. Вы можете сделать что-то подобное.

var DEFERRED = require('deferred'); 
    var deferred = new DEFERRED(); 
    var i =0; 

    while(1) {  
     listingService.getListingBySlug(listing, function(error, pFoundListing) { 
    if (error) { 
     return callback(util.errorParser(error)); 
     deferred.reject(); 
     break; 
    } else if (Object.keys(pFoundListing).length) {   
     i++; 
     listing.slug = listing.slug + '-' + (i + 1); 
     if(pFoundListing) {deferred.resolve()} 
     break; 
    } 
    }); 


    deferred.promise.then(function() { 
    // You will have the listing.slug value here. 
    }); 

Btw вы не должны использовать Object.keys(), чтобы определить, пуст ли объект или нет. Просто создайте свой собственный метод isEmpty где-нибудь в файле utils и проверьте свойства. Если ваш pFoundListing очень большой, у него будет серьезная проблема с производительностью. Для небольших объектов (массива) вы не заметите разницы.

+0

Ty для ответа! Но не было бы этого потенциального цикла 1.000 раз, если обратный вызов занимает достаточно много времени? – Chry007

1

Я не имею Possiblity, чтобы проверить это, но, возможно, рекурсивная функция должна сделать:

const listingService = { 
 
    getListingBySlug(listing, callback) { 
 
    setTimeout(() => { 
 
     if (listing.slug === 'listing-5') { 
 
     callback(
 
      false, 
 
      { 
 
      name: 'Listing 1', 
 
      slug: 'listing-1', 
 
      } 
 
     ); 
 
     } 
 
     else { 
 
     callback(false, {}); 
 
     } 
 
    }, 1000); 
 
    }, 
 
}; 
 

 
function checkListingExists(slug) { 
 
    return new Promise((resolve, reject) => { 
 
\t \t const listing = { slug }; 
 
    listingService.getListingBySlug(listing, (error, pFoundListing) => { 
 
     if (error) { 
 
     reject(error); 
 
     } else if (Object.keys(pFoundListing).length) { 
 
     resolve(pFoundListing); 
 
     } else { 
 
     resolve(false); 
 
     } 
 
    }); 
 
    }); 
 
} 
 

 
function nextListing(prefix, index) { 
 
    checkListingExists(prefix + '-' + index) 
 
    .then((listing) => { 
 
    if (listing === false) { 
 
     nextListing(prefix, index + 1); 
 
    } else { 
 
     console.log(listing); 
 
    } 
 
    }) 
 
    .catch(() => { 
 
    // deal with error response 
 
    }); 
 
} 
 

 
nextListing('listing', 0);

+0

Эй! Ty для ответа! Я просто работал над рекурсивным способом решения этой проблемы. Я также считаю, что это единственный способ. Я буду тестировать и обновлять. – Chry007

+1

Учтите, что подход состоит в том, чтобы запросить запросы на сервер, пока не найдете «неиспользуемый slug», но это далеко не оптимальная производительность. Я не знаю, владеете ли вы API, но если вы это сделаете, гораздо лучше реализовать такой метод, как 'getFirstAvailableListing (slug)' или что-то подобное. –

+0

. Я владею API, но цикл должен быть где-то на сервер, не так ли? Единственный другой способ, который я могу придумать, - это получить все списки с помощью «slug = newSlug *» из базы данных, а затем определить через регулярное выражение, которое будет первым неиспользуемым slug – Chry007