promise.catch 和 console.log 的 NodeJS 错误?
NodeJS bug with promise.catch and console.log?
当 运行 下面的代码时,我会得到不同的结果,这取决于我是否 console.log("fnError: ", fnError)
注释掉了。这对我来说似乎很不对劲。
打给 console.log
的电话到底对我的承诺有何影响?
function run() {
var fn = function(){
throw new Error("incorrect message");
};
// returns a promise that should fail with
// an error object whose .message is "correct message"
var promisifiedFn = function(){
return Promise.resolve()
.then(fn)
.catch((fnError) => {
// commenting this out fixes things! //
console.log("fnError: ", fnError);
///////////////////////////////////////
fnError.message = "correct message";
throw fnError;
})
}
promisifiedFn().catch((e) => {
console.log("caught error.message:", e.message);
console.log("caught error:", e);
});
}
run();
以上产生:
// fnError: Error: incorrect message
// at fn (/Users/sam/dev/ethereum/pennyeth/js/temp.js:18:9)
// at <anonymous>
// at process._tickCallback (internal/process/next_tick.js:169:7)
// ...
// caught error.message: correct message
// caught error: Error: incorrect message
// at fn (/Users/sam/dev/ethereum/pennyeth/js/temp.js:18:9)
// at <anonymous>
// at process._tickCallback (internal/process/next_tick.js:169:7)
// ...
通知 "incorrect message" 被记录。如果你注释掉 console.log("fnError: ", fnError)
你会得到这个:
// caught error.message: correct message
// caught error: Error: correct message
// at fn (/Users/sam/dev/ethereum/pennyeth/js/temp.js:18:9)
// at <anonymous>
// at process._tickCallback (internal/process/next_tick.js:169:7)
// ....
运行 节点 8.0.0
我能够重现此 "bug",仅需以下 4 行。
var e = new Error('first');
console.log(e);
e.message = 'new';
console.log(e);
我试过了Chrome59,没有同样的问题
但是Node 7.9.0、Node 8.0.0、Node 8.1.2都有这个问题。
我在 GitHub #13832 上报告了一个错误,所以我们会看到它的结果。
更新 1:为了表明这不是时间问题,我们可以添加 setTimeout
调用
var e = new Error('first');
console.log(e);
setTimeout(() => { e.message = 'new'; }, 1000);
setTimeout(() => console.log(e), 2000);
即使我们等待调用 console.log()
,问题仍然存在,这让我相信输出已被缓存。
更新 2:我在 GitHub:
上收到了 mscdex 的回复
This is expected because what you're seeing is the stack trace, which includes the error message once it's generated. The stack trace is generated lazily and only once (for performance reasons), so that is why you see the same output both times.
If you however change your code to output e.message, you will see the expected change in output.
最终,mscdex 和 Bergi 都说根本原因是惰性求值。
你正在做的事情可能不是一个常见的场景,所以我以后会避免这样做,因为 node.js 团队似乎不会改变这种行为。
这是预期的行为。
记录错误(至少经过 util.inspect
或 String
)确实评估了它的 .stack
属性。实例化错误对象时不会初始化堆栈字符串,而是延迟构建以节省内存。堆栈跟踪将包含错误消息,当您更改 .message
属性 时,它会反映在堆栈跟踪中或不反映在堆栈跟踪中,具体取决于是否已经创建。
来自the V8 stack trace API description:
For efficiency stack traces are not formatted when they are captured but on demand, the first time the stack property is accessed.
来自the official node Error
documentation:
The string representing the stack trace is lazily generated when the error.stack property is accessed.
当 运行 下面的代码时,我会得到不同的结果,这取决于我是否 console.log("fnError: ", fnError)
注释掉了。这对我来说似乎很不对劲。
打给 console.log
的电话到底对我的承诺有何影响?
function run() {
var fn = function(){
throw new Error("incorrect message");
};
// returns a promise that should fail with
// an error object whose .message is "correct message"
var promisifiedFn = function(){
return Promise.resolve()
.then(fn)
.catch((fnError) => {
// commenting this out fixes things! //
console.log("fnError: ", fnError);
///////////////////////////////////////
fnError.message = "correct message";
throw fnError;
})
}
promisifiedFn().catch((e) => {
console.log("caught error.message:", e.message);
console.log("caught error:", e);
});
}
run();
以上产生:
// fnError: Error: incorrect message
// at fn (/Users/sam/dev/ethereum/pennyeth/js/temp.js:18:9)
// at <anonymous>
// at process._tickCallback (internal/process/next_tick.js:169:7)
// ...
// caught error.message: correct message
// caught error: Error: incorrect message
// at fn (/Users/sam/dev/ethereum/pennyeth/js/temp.js:18:9)
// at <anonymous>
// at process._tickCallback (internal/process/next_tick.js:169:7)
// ...
通知 "incorrect message" 被记录。如果你注释掉 console.log("fnError: ", fnError)
你会得到这个:
// caught error.message: correct message
// caught error: Error: correct message
// at fn (/Users/sam/dev/ethereum/pennyeth/js/temp.js:18:9)
// at <anonymous>
// at process._tickCallback (internal/process/next_tick.js:169:7)
// ....
运行 节点 8.0.0
我能够重现此 "bug",仅需以下 4 行。
var e = new Error('first');
console.log(e);
e.message = 'new';
console.log(e);
我试过了Chrome59,没有同样的问题
但是Node 7.9.0、Node 8.0.0、Node 8.1.2都有这个问题。
我在 GitHub #13832 上报告了一个错误,所以我们会看到它的结果。
更新 1:为了表明这不是时间问题,我们可以添加 setTimeout
调用
var e = new Error('first');
console.log(e);
setTimeout(() => { e.message = 'new'; }, 1000);
setTimeout(() => console.log(e), 2000);
即使我们等待调用 console.log()
,问题仍然存在,这让我相信输出已被缓存。
更新 2:我在 GitHub:
上收到了 mscdex 的回复This is expected because what you're seeing is the stack trace, which includes the error message once it's generated. The stack trace is generated lazily and only once (for performance reasons), so that is why you see the same output both times.
If you however change your code to output e.message, you will see the expected change in output.
最终,mscdex 和 Bergi 都说根本原因是惰性求值。
你正在做的事情可能不是一个常见的场景,所以我以后会避免这样做,因为 node.js 团队似乎不会改变这种行为。
这是预期的行为。
记录错误(至少经过 util.inspect
或 String
)确实评估了它的 .stack
属性。实例化错误对象时不会初始化堆栈字符串,而是延迟构建以节省内存。堆栈跟踪将包含错误消息,当您更改 .message
属性 时,它会反映在堆栈跟踪中或不反映在堆栈跟踪中,具体取决于是否已经创建。
来自the V8 stack trace API description:
For efficiency stack traces are not formatted when they are captured but on demand, the first time the stack property is accessed.
来自the official node Error
documentation:
The string representing the stack trace is lazily generated when the error.stack property is accessed.