Как я могу выйти из последовательности обещаний, когда массив обработан?

Я реализовал следующий пример кода в скрипте, который перебирает массив результатов и делает HTTP-запрос для каждого из них.

function sequence(array, callback) {
    return array.reduce(function chain(promise, item) {
        return promise.then(function () {
            return callback(item);
        });
    }, Promise.resolve());
};

var products = ['sku-1', 'sku-2', 'sku-3'];

sequence(products, function (sku) {
    return getInfo(sku).then(function (info) {
        console.log(info)
    });
}).catch(function (reason) {
    console.log(reason);
});

function getInfo(sku) {
    console.log('Requested info for ' + sku);
    //assume this function makes an http request and returns a  promise
}

Сценарий не завершается после обработки всех элементов массива. Как бы я приспособил его, чтобы это произошло?

Моя реализация делает вызов API и возвращает обещание:

....

}).then(function(results){
sequence(results, function(result){

    checkSpam(result).then(function(akismet){
        if(akismet) {
            //console.log('spam returned from checkspam');
            write_spam_to_file(result);
        } else {

            //console.log('no spam returned from checkspam');
        }
    })
});

}).catch(function (e) {
    console.log('Error occurred:');
    console.log(e);
});


function sequence(array, callback) {
    return array.reduce(function chain(promise, item) {
        return promise.then(function () {
            return callback(item);
        });
    }, Promise.resolve());
}

function checkSpam(entry) {

    var akismetPromise = new Promise(function resolver(resolve, reject) {
        akismet.checkSpam({
            user_agent: 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1',
            referrer: 'http://google.com',
            user_ip: entry.ip,
            comment_author: entry.poster,
            comment_content: entry.message,
            comment_type: 'forum-post'


        }, function (err, spam) {
            if (err) reject(err);
            resolve(spam);
        });

    });
    return akismetPromise;

}

person codecowboy    schedule 23.03.2016    source источник
comment
Что именно вы подразумеваете под не выходит? Вы имеете в виду, что узел не перестает работать? Вряд ли это вызвано обещаниями, скорее akismet или чем-то еще, что вы используете.   -  person Bergi    schedule 23.03.2016
comment
@Bergi Я новичок в обещаниях, поэтому не был уверен, что сделал что-то неправильно. Я добавил еще немного кода на случай, если это прольет свет. Спасибо, что посмотрели.   -  person codecowboy    schedule 23.03.2016
comment
При переборе массивов вы можете вернуть false из метода цикла, чтобы остановить итерацию.   -  person Silkster    schedule 23.03.2016


Ответы (1)


В отличие от вашего первого фрагмента, в вашем реальном коде отсутствует несколько return ключевых слов:

    …
}).then(function(results) {
    return sequence(results, function(result) {
//  ^^^^^^
        return checkSpam(result).then(function(akismet) {
//      ^^^^^^
            if (akismet) {
                return write_spam_to_file(result);
//              ^^^^^^ // assuming the write is asynchronous and returns a promise?
            }
        });
    });
}) …

Если вы не всегда возвращаете обещание из асинхронных функций (включая then обратных вызовов), цепочка обещаний не знает, что для ожидания и выполняет следующий обратный вызов, не дожидаясь каких-либо результатов.

person Bergi    schedule 23.03.2016
comment
нам нужен канонический ответ на забытые ответы, эти вопросы возвращаются тонну раз. Обещание не ждать действий или что-то в этом роде, проблема в том, что это звучит слишком обобщенно... - person Benjamin Gruenbaum; 24.03.2016
comment
@BenjaminGruenbaum: Да, но следующий канонический текст, который я собираюсь написать, касается асинхронных циклов :-) (если у нас уже нет хорошего?) - person Bergi; 24.03.2016