如何在带有promise的setTimeout中看到完整的堆栈错误跟踪

时间:2017-10-02 15:18:26

标签: javascript node.js async-await

我试图了解如何从setTimeout

引起的承诺拒绝中获得完整的堆栈跟踪

我正在运行以下示例:

'use strict';

function main() {
  f1().catch(e => {
    console.error('got error with trace:');
    console.error(e);
  });

  f2().catch(e => {
    console.error('got error with trace:');
    console.error(e);
  });
}

async function f1() {
  return new Promise((resolve, reject) => {
    reject(new Error('Error in normal flow'));
  });
}

async function f2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error('Error in timeout'));
    }, 0);
  });
}

main();

我得到了这个输出:

got error with trace:
Error: Error in normal flow
    at Promise (/Users/me/project/example.js:25:12)
    at Promise (<anonymous>)
    at f2 (/Users/me/project/example.js:24:10)
    at main (/Users/me/project/example.js:9:3)
    at Object.<anonymous> (/Users/me/project/example.js:29:1)
    at Module._compile (module.js:569:30)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)
got error with trace:
Error: Error in timeout
    at Timeout.setTimeout [as _onTimeout] (/Users/me/project/example.js:18:14)
    at ontimeout (timers.js:488:11)
    at tryOnTimeout (timers.js:323:5)
    at Timer.listOnTimeout (timers.js:283:5)

如何使用setTimeout启动的承诺的堆栈跟踪更加详细,就像没有setTimeout的承诺一样?

当我在实际生产代码中发生这种情况时,我无法确切地知道错误的起源。这使得调试非常困难。

3 个答案:

答案 0 :(得分:0)

之前我做过类似的事情:

async function f2() {
  return new Promise((resolve, reject) => {
    const potentialError = new Error('Error in timeout');
    setTimeout(() => {
      reject(potentialError);
    }, 0);
  });
}

这会导致错误,就像setTimeout之外的错误一样。无论你在哪里创建错误,都会决定你的堆栈跟踪。

对我来说,一个用例是一个超时的测试,因为承诺永远不会解决(在我的情况下,使用puppeteer和mocha / jasmine)。因为超时没有有意义的堆栈跟踪,所以我写了a wrapper around the promise that includes a setTimeout,就像这个例子一样。

答案 1 :(得分:0)

我试着这样写:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
FilterAdministratorToken=dword:0

尽量避免在非承诺回调中做任何事情。

答案 2 :(得分:0)

这里有一些不错的答案,但是尚未考虑的事情是生成堆栈跟踪非常昂贵,并且您不想一直这样做。 V8有一个出色的JIT编译器,该编译器可能会无序运行,并且必须解绕才能获得正确的堆栈跟踪。因此,只有在需要时,我们才应该为“潜在错误”生成堆栈跟踪。

async function f2() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            // Stack trace is unhelpful here.
            reject(new Error("Error in timeout"))
        }, 0)
    })
}

async function f3() {
    // This stack trace is useful here, but generating a stack trace is expensive
    // because V8 has to unravel all of its fancy JIT stuff.
    const potentialError = new Error("Error in timeout")
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(potentialError)
        }, 0)
    })
}

async function f4() {
    try {
        const result = await new Promise((resolve, reject) => {
            setTimeout(() => {
                reject(new Error("Error in timeout"))
            }, 0)
        })
        return result
    } catch (error) {
        // Override the stack trace only when you need it.
        error.stack = new Error().stack
        throw error
    }
}