我有以下内容:
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)")
立即执行(或根本没有)?答案 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 的承诺。
- 断言:IsPromise(承诺) true 。
- 断言: resultCapability 是PromiseCapability记录。
- 如果IsCallable( onFulfilled ) false ,则
- 让 onFulfilled
"Identity"
。- 如果IsCallable( onRejected ) false ,则
- 让 onRejected
"Thrower"
。- 让 fulfillReaction 成为PromiseReaction {[[Capabilities]]: resultCapability ,[[Handler]]: onFulfilled }。
- ...
醇>
这里的要点是(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)
基本相同,这就是您不会收到错误的原因。