如果你自认熟悉 Promise,来猜一下这个代码的运行结果 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
autoxbc
V2EX    Javascript

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

  •  
  •   autoxbc 2019-07-24 05:13:32 +08:00 6464 次点击
    这是一个创建于 2347 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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 教程都不合格,我还没见过合格的

    第 1 条附言    2019-07-25 01:44:16 +08:00

    继续关注这个帖子的朋友,送上一道附加题

    const OnResolved= e => console.log(e); new Promise( ( resolve , reject ) => { resolve( new Promise( ( resolve , reject ) => { resolve(42); } ) ); } ).then(onResolved); new Promise( ( resolve , reject ) => { resolve( Promise.resolve(43) ); } ).then(onResolved); Promise.resolve( new Promise( ( resolve , reject ) => { resolve(44); } ) ).then(onResolved); Promise.resolve( Promise.resolve(45) ).then(onResolved); 
    33 条回复    2019-08-01 13:42:10 +08:00
    jiangzhuo
        1
    jiangzhuo  
       2019-07-24 05:54:39 +08:00
    这有点难度……我觉得就算教程合格了,也不一定能答对,至少需要个草稿纸……

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

    我觉得能答成这样就算及格了。真要把四个 promise 一起,你还得给人家其他条件才能算出正确结果了,意义不大……
    binux
        2
    binux  
       2019-07-24 06:12:49 +08:00
    这个是大家来找茬吗?
    autoxbc
        3
    autoxbc  
    OP
       2019-07-24 06:18:00 +08:00
    @jiangzhuo #1 一个一个答对也算合格。不过我看过的教程,都没有清晰的解释 new Promise() 的行为,使得很多人说不出四段代码的关键区别
    qdwang
        4
    qdwang  
       2019-07-24 07:40:10 +08:00 via iPhone
    还真从来没在实际中用过 reject 一个 promise。能说说哪种情况下需要这么写吗
    zjsxwc
        5
    zjsxwc  
       2019-07-24 07:56:31 +08:00 via Android
    这个是最基本都 promise 用法啊,
    楼主这里相对正常使用时,奇葩一点的是被 resolve 和 reject 了一个 promise,
    当然是在 resolve 和 reject 之前执行这个 promise 里面的代码呗。
    iceheart
        6
    iceheart  
       2019-07-24 08:08:36 +08:00 via Android
    UnhandledPromiseRejectionWarning:
    ??
    jaskle
        7
    jaskle  
       2019-07-24 08:23:39 +08:00 via Android
    我决定放进 node 跑一下
    jinliming2
        8
    jinliming2  
       2019-07-24 08:25:10 +08:00   11
    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
        9
    jinliming2  
       2019-07-24 08:32:02 +08:00   1
    所以:
    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
        10
    Sparetire  
       2019-07-24 08:37:06 +08:00 via Android
    关键是 reject 不会递归地 resolve 里面的 Promise 吧,猜测那就应该是先 reject 了后面两个并打印了两个 pending 的 Promise,然后再是 resolve 42 和 reject 42
    zqx
        11
    zqx  
       2019-07-24 08:42:25 +08:00 via Android
    如果楼主没见过合格的教程,你怎么知道你的结果就是唯一正确的呢?
    Snail233
        12
    Snail233  
       2019-07-24 09:11:31 +08:00
    马克下,后面看
    temporary
        13
    temporary  
       2019-07-24 09:31:29 +08:00
    mcfog
        14
    mcfog  
       2019-07-24 09:44:04 +08:00 via Android
    这种考察是否 promise 熟悉的方式我认为不合格
    nikandaoleshenme
        15
    nikandaoleshenme  
       2019-07-24 09:47:01 +08:00
    额,表示这样的代码看都不想看,难道是真香定律 [狗头]
    daishankeke
        16
    daishankeke  
       2019-07-24 09:53:10 +08:00   1
    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
        17
    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
        18
    mcfog  
       2019-07-24 10:00:57 +08:00 via Android   3
    @jinliming2 你可以仔细看下 https://promisesaplus.com/ 这里有几个要点:1. new Promise 的行为并没有被标准化,2. promise 和 thenable 的处理是不一样的 3. 实践中一个 promise 实现却很难探测出 promise 和 thenable 的区别 4. 标准中的 onRejected 是有递归展开行为的

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

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

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


    别钻牛角尖,扣学术字眼。就那么简单。就一个语法糖,写起来、维护起来舒服而已,漫天的教程,都在扯淡。
    beginor
        20
    beginor  
       2019-07-24 10:13:14 +08:00 via Android
    既然有了 promise,还是配合 async/await 食用, 疗效更佳
    PyCode
        21
    PyCode  
       2019-07-24 11:22:44 +08:00
    所以有没有合格的教程?
    banricho
        22
    banricho  
       2019-07-24 11:31:00 +08:00
    这……无论是面试题还是业务代码都是不合格的 = =
    都什么年代了。。。
    will0404
        23
    will0404  
       2019-07-24 11:45:40 +08:00   1
    有了 async/await 再去折腾这个没必要了,即使没有 async/await,没有任何场景会需要这样写代码。
    ochatokori
        24
    ochatokori  
       2019-07-24 12:38:01 +08:00 via Android
    js 考题日常
    为了整人出题…
    libo930920
        25
    libo930920  
       2019-07-24 13:42:39 +08:00
    仔细看过 Promise A+规范的,基本都应该能答出来的吧
    abcdGJJ
        26
    abcdGJJ  
       2019-07-24 16:37:56 +08:00
    @temporary node 10.7 上是一致的 node 10 好像改过 promise
    azh7138m
        27
    azh7138m  
       2019-07-24 18:27:43 +08:00
    @zqx 标准是唯一且正确的,可以看标准。
    教程不过是一个演绎(有的连演绎都算不上),可以选择不看。
    Raymon111111
        28
    Raymon111111  
       2019-07-24 18:51:23 +08:00
    那 js 里
    [ + { = ?
    ] + } 呢?
    zqx
        29
    zqx  
       2019-07-24 19:00:54 +08:00 via Android
    @azh7138m 标准也是教程
    azh7138m
        30
    azh7138m  
       2019-07-24 19:44:38 +08:00
    @zqx 那你应该是没看过标准,standard 和 tutorial 可完全不是一个东西
    autoxbc
        31
    autoxbc  
    OP
       2019-07-25 00:12:39 +08:00
    @qdwang #4 这确实不是种模式用法,但也称不上反模式,算是知识盲点吧
    zqx
        32
    zqx  
       2019-07-25 08:45:04 +08:00 via Android
    @azh7138m 有意思,公开的东西想看就看没什么门槛,好像比别人高级?
    libook
        33
    libook  
       2019-08-01 13:42:10 +08:00
    这个知识很有趣,但对教程的全盘否定有些太偏激了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     976 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 37ms UTC 19:01 PVG 03:01 LAX 11:01 JFK 14:01
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86