异步承诺中未处理的承诺拒绝

时间:2015-10-20 12:17:14

标签: javascript promise es6-promise oboe.js

我使用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 个答案:

答案 0 :(得分:2)

你的双簧管问题是基于Oboe流入JSON的事实,所以我们事先不知道有多少承诺,所以我们不能提前将责任附加到Promise.all。我们可以"宣传"双簧管能够在其方法中返回承诺。

通常,我使用RxJS自动从事件发射器创建流 - 而RxJS的方法已经可以返回promises然后聚合它。但是 - 因为我不想在这里建立第三方图书馆,而且教学价值较低 - 让我们自己实施:

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中),则不会记录错误。