为什么可以将非函数参数传递给Promise.then()而不会导致错误?

时间:2017-02-07 16:15:33

标签: javascript node.js promise

我有以下内容:

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没有引发异常?

3 个答案:

答案 0 :(得分:3)

代码

console.log("before 3 seconds (instantly)")

表达式,特别是函数调用表达式。无论出现在哪里,它都意味着同样的事情,包括外观作为Promise的.then()方法的参数。与任何其他类似语言一样,函数调用中使用的表达式在函数调用之前进行评估,因此

.then(console.log("before 3 seconds (instantly)"))

会导致console.log()函数被称为 first ,然后返回值传递给.then()。这就是您立即在控制台中看到消息的原因。

允许将undefined传递给.then(),因为console.log()返回的是什么,所以没有错误。

如果你希望在履行承诺时发生console.log(),你可以将它包装在一个函数中:

.then(function() { console.log("after 3 seconds"); })

答案 1 :(得分:1)

  

为什么可以将非函数参数传递给Promise.then()而不会导致错误?

是。应忽略所有非函数参数。见下文。

  

为什么console.log("在2秒之前(立即)")立即执行(或根本没有)?

因为在JS中,函数调用的参数会立即被评估(应用顺序)。

  

为什么当我没有传递函数时,第二个Promise没有引发异常?

因为console.log返回undefined.then()没有参数是合法的(因为两个处理程序都是可选的)。在您的示例中,console.log()返回undefined,因此它就像调用.then()而没有参数。

但即使用一些不是函数的参数调用它们,它们仍然会被忽略。例如,即使在这个例子中,“确定”也是如此。仍会在最后到达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不是函数,则必须忽略它。
  •   

答案 2 :(得分:1)

  

为什么console.log("before 2 seconds (instantly)")会立即执行(或根本没有)?

在调用函数之前评估函数的参数。当您执行alert(1+2)时,您希望首先评估1+2,当您执行alert(console.log("..."))时,您应该首先评估console.log("...")then没有什么特别之处;它只是一个常规函数,其参数与任何其他函数的参数一样对待。

  

为什么当我没有传递函数时,第二个Promise没有引发异常?

因为console.log返回undefined,语言规范(ECMAScript 2015)说明了当您致电then(undefined)时会发生什么,并且它没有抛出异常。让我们来看看它的作用:

  

25.4.5.3.1 PerformPromiseThen ( promise, onFulfilled, onRejected, resultCapability )

     

抽象操作PerformPromiseThen执行“then”   使用 onFulfilled onRejected 作为承诺的操作   和解行动。结果是 resultCapability 的承诺。

     
      
  1. 断言:IsPromise(承诺 true
  2.   
  3. 断言: resultCapability 是PromiseCapability记录。
  4.   
  5. 如果IsCallable( onFulfilled false ,则      
        
    1. onFulfilled "Identity"
    2.   
  6.   
  7. 如果IsCallable( onRejected false ,则      
        
    1. onRejected "Thrower"
    2.   
  8.   
  9. fulfillReaction 成为PromiseReaction {[[Capabilities]]: resultCapability ,[[Handler]]: onFulfilled }。
  10.   
  11. ...
  12.   

这里的要点是(3)和(5)。在(3)中,由于 onFulfilled undefined,因此IsCallable( onFulfilled false ,因此 onFulfilled 设置为 "Identity" 。然后,在(5)中,使用[[Handler]] onFulfulled 创建PromiseReaction,我们知道 "Identity"

以下是关于 "Identity" PromiseReaction Records部分的内容:

  

如果[[Handler]]为 "Identity" ,则它等同于只返回其第一个参数的函数。

所以你有它。致电then(undefined)与致电then(a => a)基本相同,这就是您不会收到错误的原因。