为什么可以传递一个非函数参数给Promise.then()而不会导致错误?
我有以下几点:
new Promise(resolve => setTimeout(resolve, 2000)) .then(() => console.log("after 2 seconds")); new Promise(resolve => setTimeout(resolve, 3000)) .then(console.log("before 3 seconds (instantly)"));
产生以下输出:
> node index.js before 3 seconds (instantly) after 2 seconds
Promise.then()期望一个onFulfilled
函数,但我通过console.log("before 2 seconds (instantly)")
,这不是一个函数。 两部分问题:
- 为什么
console.log("before 2 seconds (instantly)")
(或根本)执行? - 为什么第二个Promise在我没有传入函数的时候会引发exception呢?
代码
console.log("before 3 seconds (instantly)")
是一个expression式 ,特别是一个函数调用expression式。 无论出现什么地方,它都表示相同的事物,包括外观作为Promise的.then()
方法的参数。 和其他类似的语言一样,函数调用中使用的expression式在函数调用之前被评估
.then(console.log("before 3 seconds (instantly)"))
会导致首先调用console.log()
函数,然后将返回值传递给.then()
。 这就是为什么您立即在控制台中看到消息的原因。
将undefined
传递给.then()
是允许的,因为这是console.log()
返回的内容,所以不会引发错误。
如果你希望console.log()
在Promise被实现时发生,你可以把它包装在一个函数中:
.then(function() { console.log("after 3 seconds"); })
为什么可以传递一个非函数参数给Promise.then()而不会导致错误?
是。 所有的非函数参数应该被忽略。 见下文。
为什么console.log(“2秒(即刻)”之前)立即(或根本)执行?
因为在JS中,函数调用的参数是即时评估的(适用顺序)。
为什么第二个Promise在我没有传入函数的时候会引发exception呢?
由于console.log
返回undefined
, .then()
没有参数是合法的(因为这两个处理程序是可选的)。 在你的例子console.log()
返回未定义,所以就像调用.then()
没有参数。
但即使被称为一些不是函数的参数,它们仍然会被忽略。 例如,即使在这个例子中,'ok'仍然会到达console.log
末尾,这可能令人惊讶:
Promise.resolve('ok') .then() .then(false) .then(null) .then(1) .then('x') .then([1, 2, 3]) .then({a: 1, b: 2}) .then(console.log);
参见Promises / A +规范,第2.2.1节描述了.then()
方法的参数:
2.2.1 onFulfilled和onRejected都是可选参数:
- 如果onFulfilled不是函数,则必须忽略。
- 如果onRejected不是一个函数,它必须被忽略。
为什么
console.log("before 2 seconds (instantly)")
(或根本)执行?
函数的参数在函数被调用之前被评估。 当你做alert(1+2)
你期望1+2
被首先评估,当你做alert(console.log("..."))
你也应该期望console.log("...")
要先评估。 那时没什么特别的; 它只是一个常规函数,其参数与其他函数的参数一样。
为什么第二个Promise在我没有传入函数的时候会引发exception呢?
由于console.log
返回undefined
,并且语言规范( ECMAScript 2015 )说明当您调用then(undefined)
时应该发生什么,并且不会引发exception。 我们来看看它的function:
25.4.5.3.1 PerformPromise Then(promise,onFulfilled,onRejected,resultCapability)
抽象操作PerformPromise然后使用onFulfilled和onRejected执行对promise的“then”操作作为其结算操作。 结果是resultCapability的承诺。
- 断言:IsPromise( 承诺 )是真实的 。
- 断言: resultCapability是一个PromiseCapabilitylogging。
- 如果IsCallable( onFulfilled )为false ,那么
- 让实现成为
"Identity"
。- 如果IsCallable( onRejected )是false ,那么
- 让“ 拒绝”为
"Thrower"
。- 让fulfillReaction成为PromiseReaction {[[Capabilities]]: resultCapability ,[[Handler]]: onFulfilled }。
- …
这里的要点是(3)和(5)。 在(3)中,由于onFulfilled是undefined
,IsCallable( onFulfilled )是错误的 ,所以onFulfilled被设置为"Identity"
。 然后,在(5)中,用[[Handler]] onFulfulled创build一个PromiseReaction ,我们知道它是"Identity"
。
以下是PromiseReactionlogging关于"Identity"
:
如果[[Handler]]是
"Identity"
那么它相当于一个简单地返回第一个参数的函数。
所以你有它。 then(undefined)
调用then(undefined)
与调用then(a => a)
基本相同,这就是为什么你没有得到一个错误。