如果你自认熟悉 Promise,来猜一下这个代码的运行结果

2019-07-24 05:13:32 +08:00
 autoxbc
const onResolved = e => console.log('resolve , ', e );
const onRejected = e => console.log('reject , ', e );

new Promise( ( resolve , reject ) => {
	resolve( new Promise( ( resolve , reject ) => {
		resolve(42);
	} ) );
} ).then( onResolved , onRejected );

new Promise( ( resolve , reject ) => {
	resolve( new Promise( ( resolve , reject ) => {
		reject(42);
	} ) );
} ).then( onResolved , onRejected );

new Promise( ( resolve , reject ) => {
	reject( new Promise( ( resolve , reject ) => {
		resolve(42);
	} ) );
} ).then( onResolved , onRejected );

new Promise( ( resolve , reject ) => {
	reject( new Promise( ( resolve , reject ) => {
		reject(42);
	} ) );
} ).then( onResolved , onRejected );

如果猜错了,说明之前看的 Promise 教程都不合格,我还没见过合格的

5756 次点击
所在节点    JavaScript
33 条回复
jiangzhuo
2019-07-24 05:54:39 +08:00
这有点难度……我觉得就算教程合格了,也不一定能答对,至少需要个草稿纸……

应该很多人挨个运行能答出来,比如
resolve , 42
reject , 42
reject , 一个 Promise
reject,一个 Promise 并且里面那个的 reject 没有 handle

我觉得能答成这样就算及格了。真要把四个 promise 一起,你还得给人家其他条件才能算出正确结果了,意义不大……
binux
2019-07-24 06:12:49 +08:00
这个是大家来找茬吗?
autoxbc
2019-07-24 06:18:00 +08:00
@jiangzhuo #1 一个一个答对也算合格。不过我看过的教程,都没有清晰的解释 new Promise() 的行为,使得很多人说不出四段代码的关键区别
qdwang
2019-07-24 07:40:10 +08:00
还真从来没在实际中用过 reject 一个 promise。能说说哪种情况下需要这么写吗
zjsxwc
2019-07-24 07:56:31 +08:00
这个是最基本都 promise 用法啊,
楼主这里相对正常使用时,奇葩一点的是被 resolve 和 reject 了一个 promise,
当然是在 resolve 和 reject 之前执行这个 promise 里面的代码呗。
iceheart
2019-07-24 08:08:36 +08:00
UnhandledPromiseRejectionWarning:
??
jaskle
2019-07-24 08:23:39 +08:00
我决定放进 node 跑一下
jinliming2
2019-07-24 08:25:10 +08:00
promise 的 resolve 是递归的,只要 resolve 一个 promise,就会继续等待这个 promise。
而 reject 碰到就直接返回,如果 reject 的是一个 promise,这个 promise 不会被等待。
所以:
第一个 外层 promise 里 resolve 了一个 ( resolve 的 promise ),所以 then 的结果会递归等待里面的 promise 返回,里面的 promise resolve 了一个 42,所以得到了 “ resolve 的 42 ”。
第二个 外层 promise 里 resolve 了一个 ( reject 的 promise ),所以 then 的结果会递归等待里面的 promise 返回,里面的 promise reject 了一个 42,碰到 reject 直接返回,被 then 的第二个参数抓到,所以得到了 “ reject 的 42 ”。
第三个和第四个 外层 promise 直接 reject 了一个 promise (不管这个 promise 具体是啥),所以直接返回,被 then 的第二个参数抓到,所以得到 “ reject 的 promise<xxx>”。
其中第三个因为内层 promise 是 resolve 的 42,所以结果是 “ reject 的 promise<resolve 42>”。
而第四个因为内层 promise 是 reject 的 42,外层 promise 被 then 的第二个参数抓住了,但内层的没有,所以结果是 “ reject 的 promise<reject 42> 并带有一个未捕获的来自内部 promise 的异常”。

不管你这个 promise 写多少层,resolve 都会递归下去,一旦碰到 reject 立即返回。
jinliming2
2019-07-24 08:32:02 +08:00
所以:
const a = async () => {
xxxxx;
return promise;
};
await a();
如果 xxxxx 里没用到 await 语句,最后 return 了一个 promise,那么 a 的 async 标志可以去掉,变成一个普通函数。因为加上 async 标志,相当于是 resolve 了两次,而去掉就相当于变成 resolve 一次。(最后调用的时候依然得 await,像这样:)

const a = () => {
xxxxx;
return promise;
};
await a();
Sparetire
2019-07-24 08:37:06 +08:00
关键是 reject 不会递归地 resolve 里面的 Promise 吧,猜测那就应该是先 reject 了后面两个并打印了两个 pending 的 Promise,然后再是 resolve 42 和 reject 42
zqx
2019-07-24 08:42:25 +08:00
如果楼主没见过合格的教程,你怎么知道你的结果就是唯一正确的呢?
Snail233
2019-07-24 09:11:31 +08:00
马克下,后面看
temporary
2019-07-24 09:31:29 +08:00
mcfog
2019-07-24 09:44:04 +08:00
这种考察是否 promise 熟悉的方式我认为不合格
nikandaoleshenme
2019-07-24 09:47:01 +08:00
额,表示这样的代码看都不想看,难道是真香定律 [狗头]
daishankeke
2019-07-24 09:53:10 +08:00
reject,promise 对象( resolved )
reject,promise 对象( rejected )
resolve,42
reject,42

我的理解:

有一个 Promise 对象我们称他为 p1
p1 在执行 resolve 时有一个参数 result,reject 执行时有一个参数 reason
先来看 resolve:
p1 的 resolve 方法被执行时,如果发现 result 是一个 Promise 对象就会这样处理:
result.then(resolve, reject)
其实是将自己的 resolve、reject 方法移交给 result,等待 result 去 resolve 之后,才会执行 p1 的 resolve,然后 p1 在 resolve 时才会执行 p1.then 里边的 onFulfilled 和 onReject 方法。
再看 reject 的情况
reject 方法不会检测 reject 时传入的 reason 是否是一个 Promise 对象,而是直接开启一个微任务清空 reject 的回调队列,同时将返回值 reason 传入,由于没有将自己的 reject 和 resolve 方法移交给 reason 这一步,所以在这题中他们要比上面的两个 resolve(new Promise)快。

简单说就是 resolve 会判断传进来的 result 参数是不是一个 Promise,是的话会移交自己的 resolve 和 reject 方法,reject 则不会。

当然... 如果你想清晰的了解具体是怎么执行的,我建议去看看那些符合 PromiseA+规范的 Promise 实现

😂这两天我正在看 Promise,如果有不对的请指出
caocong
2019-07-24 10:00:38 +08:00
Promise 内没有 resolve 是种错误的写法 会编译报错 就如上面第二个和第四个
这里主要是 resolve 的问题 并不是直觉的返回了一个 promise 对象
文档里说的很清楚了 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve

The Promise.resolve() method returns a Promise object that is resolved with a given value. If the value is a promise, that promise is returned; if the value is a thenable (i.e. has a "then" method), the returned promise will "follow" that thenable, adopting its eventual state; otherwise the returned promise will be fulfilled with the value. This function flattens nested layers of promise-like objects (e.g. a promise that resolves to a promise that resolves to something) into a single layer.

所以看啥教程 直接读文档不就好了
mcfog
2019-07-24 10:00:57 +08:00
@jinliming2 你可以仔细看下 https://promisesaplus.com/ 这里有几个要点:1. new Promise 的行为并没有被标准化,2. promise 和 thenable 的处理是不一样的 3. 实践中一个 promise 实现却很难探测出 promise 和 thenable 的区别 4. 标准中的 onRejected 是有递归展开行为的

补充我自己的回复,楼主的出题基本聚焦于不在标准中的,而且实战中属于需要避免的写法,所以不是一个好的题目,类似 i++ + ++i
hoyixi
2019-07-24 10:07:02 +08:00
其实很简单,记得早就说过了,Promise/await/async 这些都是 js 对异步回调的语法糖,根本不是啥高深玩意,你越往深里想,越是把简单的事情想复杂。

Promise 的 resolve,一定会逐层 resolve,为啥,就好比你 callback 里又有 callback,不 callback 到最后,根本不知道结果;

Promise 的 reject,直接返回 reject 的值, 为啥,就好比你最外层 callback 直接错误,还往里层走个屁。


别钻牛角尖,扣学术字眼。就那么简单。就一个语法糖,写起来、维护起来舒服而已,漫天的教程,都在扯淡。
beginor
2019-07-24 10:13:14 +08:00
既然有了 promise,还是配合 async/await 食用, 疗效更佳

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/585619

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX