Что использовать вместо Promise.all(), когда вам нужны все результаты независимо от каких-либо отклонений

Я использую библиотеку обещаний Bluebird в проекте node.js. У меня есть две операции, которые возвращают обещания, и я хочу знать, когда обе они будут выполнены, разрешены или отклонены, и мне нужны возвращаемые значения от обоих. Я читаю содержимое нескольких файлов, и некоторые из файлов могут не существовать, и это нормальное условие, поэтому, хотя fs.readFileAsync() завершится ошибкой, если файл не существует, мне все равно нужны результаты другой операции чтения.

Promise.all(p1, p2) отклонит, если p1 или p2 отклонятся, и я не думаю, что обязательно получу данные от другого.

Какая из всех других операций Bluebird (.some(), .any(), .settle() и т. д.) больше всего подходит для этой ситуации? И как данные передаются обратно, чтобы вы могли сказать, какие из них были успешными, а какие нет?


person jfriend00    schedule 22.09.2014    source источник
comment
другой тип вопроса: если вам удобно использовать обратные вызовы и вы даже пишете код с промисами, зачем вам возиться с fs.readFileSync вместо того, чтобы просто использовать fs.readFile?   -  person Mike 'Pomax' Kamermans    schedule 22.09.2014
comment
@Mike'Pomax'Kamermans - я использую fs.readFileAsync, который возвращает обещание (это обещанная версия fs.readFile, а не версия обратного вызова) и является асинхронным. Это отличается от fs.readFileSync, который является синхронным (не использует обратные вызовы или промисы). Я использую промисы, потому что с ними намного проще правильно обрабатывать ошибки, и когда вы ожидаете выполнения нескольких асинхронных действий, они намного проще.   -  person jfriend00    schedule 22.09.2014
comment
ха, совершенно пропустил этот A. Показывает, как много я использую простой узел ›_›   -  person Mike 'Pomax' Kamermans    schedule 22.09.2014


Ответы (2)


Это было бы действительно .settle. Settle берет массив промисов и возвращает PromiseInspection экземпляров для всех из них, когда они разрешаются. Затем вы можете проверить, выполнены ли они или отклонены, и извлечь их значение.

Например:

Promise.settle(['a.txt', 'b.txt'].map(fs.readFileAsync)).then(function(results){
    // results is a PromiseInspetion array
    console.log(results[0].isFulfilled()); // returns true if was successful
    console.log(results[0].value()); // the promise's return value
});

Ваш вариант использования - это то, для чего существует Promise.settle.

person Benjamin Gruenbaum    schedule 22.09.2014
comment
Спасибо - я просто публиковал свой ответ, пока вы публиковали свой. В конце концов я разобрался с .settle(), но нет никакой документации о том, как его использовать, поэтому мне потребовались часы в отладчике, чтобы, наконец, понять что-то работоспособное. Мне буквально пришлось изучить аргументы в отладчике, чтобы узнать, как получить из них данные. Этот кусок документа мог бы серьезно использовать несколько хороших примеров. Кроме того, как можно узнать, что .settle() принимает второй аргумент, который является функцией, которая будет вызываться для каждого элемента в массиве? это где-то объяснялось для .settle()? - person jfriend00; 22.09.2014
comment
Кроме того, .settle() отклоняется, если все входные промисы отклонены, но выполняется, если хотя бы одно из них выполнено? Также было бы полезно увидеть это в документе. - person jfriend00; 22.09.2014
comment
@ jfriend00 все функции Bluebird имеют статическую версию наряду с версией экземпляра. У вас есть Promise.map(arr, fn) и promiseArr.map(fn) Promise.filter(arr, fn) и promiseArr.filter(fn) и т. д. Я отредактирую документацию, чтобы добавить пример для расчета. - person Benjamin Gruenbaum; 22.09.2014
comment
Урегулирование @jfriend00 всегда выполняется, оно будет выполняться со всеми PromiseInspection отклоненными. - person Benjamin Gruenbaum; 22.09.2014
comment
Хм. Хорошо, это еще одна полезная вещь, которую нужно знать. Рад, что вы будете улучшать документ. Обратите внимание, что я не мог понять, что такое PromiseInspection (пока не посмотрел на него в отладчике) или как его использовать. Он упоминается ровно один раз в .settle() со ссылкой на какое-то другое место в документе, где это слово не используется. Даже поиск в гугле не дал полезной информации. Я был совершенно сбит с толку. - person jfriend00; 22.09.2014
comment
@ jfriend00 большое спасибо за отзыв, я определенно буду рассматривать (и ценю) запросы на получение документов, поэтому, пожалуйста, делайте их, если вы считаете, что что-то еще можно/нужно прояснить. Проблема также сработает, если вы считаете, что что-то неясно, но не хотите делать пиар. Я недавно внес изменения здесь: gitanthub.com/petkaantonov. / дайте мне знать, если вы считаете, что это достаточно хорошо разъясняет .settle. - person Benjamin Gruenbaum; 22.09.2014
comment
Отличное улучшение! Спасибо. Я все еще изучаю github, поэтому, возможно, сейчас лучше зарегистрировать проблему. Вы можете показать, что r.value() должен быть доступен только внутри if (r.fulfilled()), так как вам в значительной степени придется использовать его таким же образом с .settle(), поскольку вы не можете заранее знать его состояние. - person jfriend00; 22.09.2014
comment
Давайте продолжим обсуждение в чате. - person Benjamin Gruenbaum; 22.09.2014
comment
set не выполняет никакой функции, он просто принимает массив? - person Esailija; 01.10.2014
comment
@Esailija О да, в этом нет никакого смысла, урегулирование просто устанавливает значения. Мне нравится, что у нас была вся эта дискуссия, а я ничего не заметил :D - person Benjamin Gruenbaum; 02.10.2014

Только попробовав разные варианты, а затем, в конечном счете, пройдя код в отладчике, я понял, как это сделать с помощью .settle():

// display log files
app.get('/logs', function(req, res) {
    var p1 = fs.readFileAsync("/home/pi/logs/fan-control.log");
    var p2 = fs.readFileAsync("/home/pi/logs/fan-control.err");
    Promise.settle([p1, p2]).spread(function(logFile, errFile) {
        var templateData = {logData: "", errData: ""};
        if (logFile.isFulfilled()) {
            templateData.logData = logFile.value();
        }
        if (errFile.isFulfilled()) {
            templateData.errData = errFile.value();
        }
        res.render('logs', templateData);
    }).catch(function(e) {
        console.log("err getting log files");
        // figure out what to display here
        res.render(e);
    });
});

Если появится кто-нибудь из команды Bluebird, в документации по использованию .settle() не хватает примерно 2/3 того, что необходимо для понимания того, как его использовать. Он ссылается на PromiseInspection, но ничего не говорит о том, как его использовать. Простой пример кода в документе для .settle() и того, как вы проверяете результаты, возвращаемые .settle(), сэкономил бы часы времени.

person jfriend00    schedule 22.09.2014