为什么可以传递一个非函数参数给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然后使用onFulfilledonRejected执行对promise的“then”操作作为其结算操作。 结果是resultCapability的承诺。

  1. 断言:IsPromise( 承诺 )是真实的
  2. 断言: resultCapability是一个PromiseCapabilitylogging。
  3. 如果IsCallable( onFulfilled )为false ,那么
    1. 实现成为"Identity"
  4. 如果IsCallable( onRejected )是false ,那么
    1. 让“ 拒绝”"Thrower"
  5. fulfillReaction成为PromiseReaction {[[Capabilities]]: resultCapability ,[[Handler]]: onFulfilled }。

这里的要点是(3)和(5)。 在(3)中,由于onFulfilledundefined ,IsCallable( onFulfilled )是错误的 ,所以onFulfilled被设置为"Identity" 。 然后,在(5)中,用[[Handler]] onFulfulled创build一个PromiseReaction ,我们知道它是"Identity"

以下是PromiseReactionlogging关于"Identity"

如果[[Handler]]是"Identity"那么它相当于一个简单地返回第一个参数的函数。

所以你有它。 then(undefined)调用then(undefined)与调用then(a => a)基本相同,这就是为什么你没有得到一个错误。