我怎么知道哪些处理程序在 promise 中抛出错误?

How do I know which handlers throw error in promise?

假设我有如下承诺:

p.then(Task1)
 .then(Task2)
 .then(Task3)
 .catch(errorHandler);

Task2遇到错误时,如何知道错误来自Task2 in catch?

你可以这样做;

Promise.resolve(21).then(v => v*2)
                   .then(v => {
                                try { throw new Error(v + " is immutable") } // assuming that your code results an error
                                catch(err){ return Promise.reject({message: "2nd then stage threw an error", err:err}) }
                              })
                   .then(v => v)
                   .catch(err => console.log(err.message, "\n",err.err.message));

为了知道最终捕获中的(异步)错误来自所有浏览器中的 Task2,您可以捕获它、标记它并重新抛出它:

var tag = (e, name) => (e.isFrom = name, Promise.reject(e));

p.then(Task1)
 .then(Task2)
 .catch(e => tag(e, "Task2"))
 .then(Task3)
 .catch(errorHandler);

不幸的是,这也会捕获来自 Task1p 的错误,因此您还需要一个 "catch-bypass":

p.then(Task1)
 .then(result => Task2(result).catch(e => tag(e, "Task2")))
 .then(Task3)
 .catch(errorHandler);

这使得 Task1 或更早的 "go around"(即绕过)我们对 Task2.

的任何错误

之所以可行,是因为我们将 catch 放在 .then 的成功回调中。每个 .then 都有一个隐含的第二个参数,它是一个错误处理程序,很像 .catch,除了它不捕获相应的成功回调,在本例中 Task2 和我们的捕获,只有链上的先前错误(即来自 Task1 或任何先前步骤的错误)。

省略错误回调意味着"pass this through unchanged"。即与此处的 e => Promise.reject(e) 相同。

let tag = (e, name) => (e.isFrom = name, Promise.reject(e));

let a = () => Promise.resolve();
let b = () => Promise.reject(new Error("Fail"));
let c = () => Promise.resolve();
let x = () => null.f();

let foo = failFirstStep => Promise.resolve()
.then(failFirstStep? x : a)
.then(() => b().catch(e => tag(e, "b")))
.then(c)
.catch(e => console.log((e.isFrom || "something else") + " failed"));

foo(false).then(() => foo(true));

概括地说,您可以改为标记函数,但我发现很难以一种惯用的方式进行,并且不会影响可读性或时间安排,所以我将把它留作练习。在实践中,有一个 ,但我发现这种技术足够有趣,可以涵盖,并且在某些情况下很有用。

大多数浏览器都支持 error.stack 属性,一些现代浏览器甚至支持异步调用堆栈:

let a = () => Promise.resolve();
let b = () => Promise.reject(new Error("Fail"));
let c = () => Promise.resolve();

Promise.resolve().then(a).then(b).then(c).catch(e => console.log(e.stack));

在 Firefox 48 中输出:b@http://stacksnippets.net/js:14:30.

在 Chrome 52 中输出:Error: Fail at b (http://stacksnippets.net/js:14:30).

这是最惯用的解决方案,因为它不会影响代码的编写方式。不幸的是,并非所有浏览器都支持异步调用堆栈,并且输出因浏览器而异,因为它用于调试。

大家好!我自己研究过演示代码。

希望大家可以看看我的回答,好不好。


简介:

It shows how to trace promise in each handler, used customized error handler to catch error. To understand the workflow of promise.

You can copy the following demonstrated code and paste in your node.js. According to the example and log message, it's good for the developers to learn promise.


使用的promise模块如下:

  • 蓝鸟

演示代码如下:

var Promise = require('bluebird');

// You can input any argument in this function to test workflow of promise 
function testPromise(input) {
    let promise = Promise.resolve(input);
    promise
      .then(makeTask('Task1'))
      .then(makeTask('Task2'))
      .then(makeTask('Task3'))
      .catch(makeErrorPredicate('Task1'), taskLog('Task1'))
      .catch(makeErrorPredicate('Task2'), taskLog('Task2'))
      .catch(makeErrorPredicate('Task3'), taskLog('Task3'))
}

// define task handler functions
function makeTask(task) {
    return function task1Handler(input) {
        if (input === task) {
            throw new Error(task)
        }            
        return input
    }
}

// custom error that it checks error message 
function makeErrorPredicate(msg) {
    return function taskError(err) {
        var result = err.message === msg;
        console.log(msg + ': ' + result)
        return result;
    }
}

// hint the error when the error has matched
function taskLog(msg) {
    return function thelog(err) {
        console.log('It\'s ' + msg)
    }  
}

范例:

>testPromise('Task1')
Task1: true
It's Task1

>testPromise('Task2')
Task1: false
Task2: true
It's Task2

>testPromise('Task3')
Task1: false
Task2: false
Task3: true
It's Task3

从上面的例子我们可以知道:

输入为'Task1'时,路由为:

firstHandler -> firstCatcher

输入为'Task2'时,路由为:

firstHandler -> secondHandler -> firstCatcher -> secondCather

输入为'Task3'时,路由为:

firstHandler -> secondHandler -> thirdHandler -> firstCatcher -> secondCatcher -> thirdCatcher

所以,从上面的结果我们知道,我们可以理解 promise 是如何工作的。


如果大家对这个答案是否满意,请告诉我,谢谢。

由于承诺链无法保存此信息,因此您需要将其存储在某个地方。两种解决方案:

装饰错误:

p.then(Task1)
 .then(function() {
    try {
      Task2();
    } catch (e) {
      e.isFromTask2 = true;
      throw e;
    } 
  })
 .then(Task3)
 .catch(errorHandler); // now you can check err.isFromTask2

使用承诺链的范围:

{
  let isFromTask2 = false;
  p.then(Task1)
   .then(function() {
      try {
        Task2();
      } catch (e) {
        isFromTask2 = true;
        throw e;
      } 
    })
   .then(Task3)
   .catch(errorHandler); // now you can check isFromTask2
}