Ранний выход из цикла Promise.any()
концептуально проблематичен, поскольку Promise.any()
является агрегатором, а не циклом, и принимает массив промисов, каждое из которых живет своей собственной жизнью, не определяемой Promise.any()
.
Однако, начиная с массива путей, цикл, который вы ищете, может быть выражен как выражение paths.reduce(...)
, которое строит цепочку .catch()
следующим образом:
function getFirstGoodFileContent(paths) {
paths.reduce(function(promise, path) {
return promise.catch(function() {
return _readFile(path);
});
}, Promise.reject()); // seed the chain with a rejected promise.
}
Catchain: кредит Берги
Построенная таким образом цепочка .catch будет переходить к следующей итерации в случае неудачи или переходить к концу цепочки в случае успеха. Это управление потоком является обратным тому, что происходит в более нормальной цепочке .then (засеянной выполненным обещанием).
Но это еще не все. Требуется дополнительное условие, а именно «досрочно выйти из цикла [Promise.any], если я получаю сообщение об ошибке, отличном от «файл не найден». Это очень просто встраивается в цепочку перехвата, отправляя все ошибки, кроме FILE_NOT_FOUND, по пути успеха, таким образом:
- осуществление необходимого управления потоком (пропуская остальную часть цепочки), но
- заканчивая состоянием ошибки, идущим по пути успеха - нежелательным, но исправимым.
function getFirstGoodFileContent(paths) {
paths.reduce(function(promise, path) {
return promise.catch(function() {
return _readFile(path).catch(function(err) {
if (err.code == FILE_NOT_FOUND) {
throw err; // Rethrow the error to continue down the catch chain, seeking a good path.
} else {
return { isError: true, message: err.code }; // Skip the rest of the catch chain by returning a "surrogate success object".
}
});
});
}, Promise.reject()).then(function(fileContent) {
// You will arrive here either because :
// * a good path was found, or
// * a non-FILE_NOT_FOUND error was encountered.
// The error condition is detectable by testing `fileContent.isError`
if (fileContent.isError) {
throw new Error(fileContent.message); // convert surrogate success to failure.
} else {
return fileContent; // Yay, genuine success.
}
});
}
Итак, теперь вы можете позвонить:
getFirstGoodFileContent([
'./foo/file1.yaml',
'./foo/file2.yaml',
'./foo/file3.yaml'
]).then(function(fileContent) {
_console.log(fileContent);
}, function(error) {
// error will be due to :
// * a non-FILE_NOT_FOUND error having occurred, or
// * the final path having resulted in an error.
console.log(error);
});
person
Roamer-1888
schedule
04.02.2016
Promise.any
не принимает обратный вызов? А цикла все равно нет, их ждут параллельно? Я бы рекомендовал написать это вручную, используяreduce
или рекурсию. - person Bergi   schedule 04.02.2016Promise.any
не принимает обратный вызов. Я хочу, чтобы файлы проверялись последовательно, а следующий только в том случае, если предыдущий не существует. Во всех остальных случаях я хочу получить ошибку. В настоящее время я реализовал это с помощьюPromise.each
и глобальногоvar
, но я подумал, что есть лучшее решение. Я снова начну думать об использованииPromise.reduce
. - person k7sleeper   schedule 04.02.2016reduce
от вызова аккумулятора, если я успешно прочитал файл. - person k7sleeper   schedule 04.02.2016