如果我们有:
const foo = Promise.resolve(1);
则最终我们从 foo
中得到的是 1
这个值。
如果像下面这样,从 bar
中能得到的是什么:
const foo = Promise.resolve(1);
const bar = Promise.resolve(foo);
其实得到的也是 1
。MDN[1] 文档中有相关解释:
The
Promise.resolve()
method returns aPromise
object that is resolved with a given value. If the value is a promise, that promise is returned.
注意后面那句,如果传给 resolve()
的参数是一个 promise,则直接返回那个 promise。
由此,我们知道上例中 foo
和 bar
引用的其实是同一个对象:
const foo = Promise.resolve(1);
const bar = Promise.resolve(foo);
// true
console.log(foo === bar);
1有意思的地方
那么,Promise.resolve()
怎么判断传入的参数是一个 promise ?
如果你修改了 foo.constructor
属性,会发现 foo
就不再等于 bar
了(SOURCE[2]):
const foo = Promise.resolve(1);
foo.constructor = {};
const bar = Promise.resolve(foo);
// false
console.log(foo === bar);
所以我们猜测它判断参数是否是 promise 依据的是参数的 constructor
属性。
(你可能能会说为什么不用 instanceof
来判断,因为改变 constructor 属性,instanceof
仍然是返回 true
,所以用它判断是不可靠的)。
另外,Object.setPrototypeOf()
也能达到修改 constructor
的效果,这就有了另一个有意思的用法:a Promise of a Promise[3]。
2A promise of a promise
既然 resolve()
入参如果是 Promise
对象,会直接被返回出去。我们比较叛逆,想实现一个传入的是 Promise
,resolved 的值也是 Promise
,怎么搞?
先试试下面这种写法(改 construcotr
属性):
const foo = Promise.resolve(1);
foo.constructor = {};
const bar = Promise.resolve(foo);
// false
console.log(foo === bar);
// 1 false
bar.then(v => console.log(v, bar === foo));
行不通,resolved 的值是 1
,我们想要的是 v
和 foo
引用的是同一个对象(都是Promise
)。
再试试这种写法:
const foo = Promise.resolve(1);
Object.setPrototypeOf(foo, null);
const bar = Promise.resolve(foo);
// false
console.log(foo === bar);
// true
bar.then(v => console.log(v === foo));
成功。
3注意
这样写代码并没有什么意思,而且真要把 v
当 Promise
来用,还得加一句:
Object.setPrototypeOf(v, Promise.prototype);
以恢复 v
的原型链。
不过本文的主要用意,是让你了解 Promise.resolve()
方法以及关注对象的 constructor
属性在某些方面的用途。
要留心的是,Promise.reject()
并不遵从相同的范式。
4总结
对于 Promise.resolve()
,如果传参是一个 promise,则会直接返回该 promise;但如果修改了参数的 constructor
属性,它会返回一个新的 promise
(只是引用不同,最终 resolved 值是相同的,可以认为该参数变成了一个 thenable);如果修改了参数的 prototype
,则 resolved 值直接变为参数本身(如同传的不是 promise 一样)。
参考资料
MDN: Promise.resolve(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
[2]
Promise.resolve() makes decisions based on the .constructor property of its argument: https://twitter.com/addaleax/status/1382039026883047428
[3]
A Promise of a Promise: https://twitter.com/JFieldEffectT/status/1382077150002569218
原文始发于微信公众号(背井):Promise.resolve() 的魔鬼细节
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/246659.html