我怎么知道哪些处理程序会在承诺中出错?

时间:2016-08-30 09:34:41

标签: javascript node.js error-handling promise bluebird

假设我有以下承诺:

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

Task2 遇到错误时,我怎么知道错误来自 catch 中的 Task2

5 个答案:

答案 0 :(得分:2)

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

我希望每个人都可以查看我的答案,不管是好还是不好。

简介:

  

它显示了如何在每个处理程序中跟踪promise,使用自定义错误处理程序来捕获错误。要了解承诺的工作流程。

     

您可以复制以下演示代码并粘贴到 node.js 中。根据示例和日志消息,开发人员学习承诺是有益的。

使用的承诺模块如下:

  • 蓝鸟

演示的代码如下:

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

输入是'任务2'时,路线是:

  

firstHandler - > secondHandler - > firstCatcher - > secondCather

输入为'任务3'时,路线为:

  

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

因此,从上面的结果我们知道,我们可以理解如何工作的承诺。

如果每个人都对这个答案感到满意,请告诉我,谢谢。

答案 1 :(得分:1)

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

解决错误:

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
}

答案 2 :(得分:0)

为了知道所有浏览器中来自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或更早版本的任何错误"绕过" (即绕过)我们的Task2

这是有效的,因为我们将catch放在.then的成功回调中。每个.then都有一个隐含的第二个参数,它是一个错误处理程序,就像.catch一样,除了它没有捕获相应的成功回调,在这种情况下Task2和我们的捕获,只有链上的先前错误(即来自Task1或任何前一步骤的错误)。

省略错误回调意味着"通过未更改的"传递它。即与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));




总而言之,你可以改为标记功能,但我觉得很难以一种惯用的方式做,并且不会干扰可读性或时间安排,所以我要离开作为一项运动。在实践中,有一个better answer,但我发现这种技术足够有趣,可以覆盖,并且在某些情况下很有用。

答案 3 :(得分:0)

大多数浏览器都支持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)

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

答案 4 :(得分:-1)

你可以这样做;



setlocal /?