Необработанное отклонение обещания в асинхронных обещаниях
Я использую Oboe.js для анализа действительно очень большого файла JSON
const promises = [];
oboe('http://domain/my-file.js')
.node('items.*', item => {
// parseItem() returns a rejected Promise because of invalid JSON items
promises.push(parseItem(item));
})
.done(() => {
Promise.all(promises).then(() => {
doSomething();
});
})
Но моя консоль браузера залита Uncaught (in promise)
, То же самое происходит, если вы пишете обещание в setTimeout()
лайк
const promises = [];
setTimeout(() => {
promises.push(Promise.reject());
}, 500);
// some time in the future
Promise.all(promises);
Что действительно странно: современные браузеры ведут себя по-разному. В Firefox Developer Edition все работает без сообщений об ошибках, а в Chrome меня заливают Uncaught (in promise)
, В Chrome вы получите сообщение мгновенно, если напишите Promise.reject();
без улова. В Firefox и Safari ничего не происходит.
Так какое решение для этого? Игнорирование сообщения? Я имею в виду, что если такое поведение действительно соответствует официальной спецификации обещаний, то обещания в асинхронном коде не имеют для меня никакого смысла.
1 ответ
Ваша проблема с Oboe основана на том факте, что Oboe передает JSON, поэтому мы никогда не знаем заранее, сколько существует обещаний, поэтому мы не можем нести ответственность за Promise.all
заблаговременно. Мы можем "обещать" Гобой, чтобы иметь возможность возвращать обещания в его методах.
Как правило, я бы использовал RxJS для автоматического создания потока из генератора событий - и методы RxJS уже могут возвращать обещания, а затем агрегировать их. Однако - поскольку я не хочу иметь здесь стороннюю библиотеку, и она имеет меньшую обучающую ценность - давайте реализуем ее сами:
function addMap(oboe) {
oboe.map = function(selector, mapper){
var promises = [];
return new Promise(function(resolve, reject){ // create a new promise
oboe.node(selector, function(match){
var result = mapper(match); // get result
// signal that we're handling the rejection to make sure it's not handled.
result.catch(function(){});
promises.push(result);
});
oboe.fail(reject);
oboe.done(function(){ resolve(promises); });
});
};
}
Что позволило бы нам сделать:
var o = oboe("foo");
addMap(o);
o.map("items.*", item => downloadItem(item)).then(result => {
// handle result here
});
Ваш setTimeout
вопрос очень надуманный Подавляющее большинство людей на практике не пишут код, который выглядит следующим образом - на практике асинхронное добавление обработчика ошибок является довольно редким случаем использования, когда не работает с API, который заставляет вас делать это (как пример Oboe.js).
Что действительно странно: современные браузеры ведут себя иначе
Это связано с тем, что Firefox использует GC для обнаружения необработанных отклонений, а Chrome - таймер. Это детали реализации - единственная гарантия, которую вы будете иметь, заключается в том, что ошибки не будут регистрироваться, если они подключены в микрозадаче (синхронно или в then
который выполняется на том же ходу).