V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
rodrick
V2EX  ›  JavaScript

请教一个 Promise 的问题

  •  1
     
  •   rodrick · 2021-01-30 15:18:18 +08:00 · 2620 次点击
    这是一个创建于 1395 天前的主题,其中的信息可能已经有所发展或是发生改变。

    分别有下面两个写法,区别就是后者用的 .catch ,为啥同用调用后打印结果不一样呢,前者打印 1,后者打印 2

    function myPromiseRace(arr) {
      return new Promise((resolve, reject) => {
        for (let item of arr) {
          item.then(
              res => { resolve(res) },
              err => { reject(err) }
            )
        }
      })
    }
    
    function myPromiseRace(arr) {
      return new Promise((resolve, reject) => {
        for (let item of arr) {
          item
            .then(
              res => { resolve(res) }
            )
            .catch(err => {
              reject(err)
            })
        }
      })
    }
    

    调用

    let p1 = Promise.reject(1),
      p2 = Promise.resolve(2),
      p3 = Promise.resolve(3)
    
    myPromiseRace([p1, p2, p3]).then(res => {
      console.log(res)
    }).catch(err => {
      console.log(err);
    })
    
    9 条回复    2021-01-30 17:30:11 +08:00
    h503mc
        1
    h503mc  
       2021-01-30 15:34:59 +08:00   ❤️ 1
    第二种写法需要 then 里的函数 reject 掉才会触发下一个的 catch
    genal
        2
    genal  
       2021-01-30 16:11:50 +08:00   ❤️ 1
    第二个 mypromise 多了个 catch,相当于多套了一层,所以第一个 promise 更慢,由于 promise 只能 resolve,reject 一次,谁快先输出谁
    genal
        3
    genal  
       2021-01-30 16:12:32 +08:00
    后面的 resolve,rejecrt 是什么不重要了,promise 只能 resolve,reject 一次
    faceRollingKB
        4
    faceRollingKB  
       2021-01-30 16:13:27 +08:00   ❤️ 5
    从 micro task 的角度看,promise 本体在 current task 中执行,then 里面的回调被添加到 micro task 队列中,而第二种写法里面的 catch 是在 then 所属的 micro task 被执行时才被添加到 micro task 队列的,所以:
    第一种写法:三个 promise 依次被添加 then 里面定义的 micro task,得到队列 p1-then 、p2-then 、p3-then,p1-then 的 reject 回调会赢得 race ;
    第二种写法:三个 promise 依次被添加 then 里面定义的 micro task,micro task 的执行结果会得到新的 promise,继而依次添加 catch 里面的 micro task,完全执行下去会有 6 个 micro task,依次是 p1-then 、p2-then 、p3-then 、p1-catch 、p2-catch 、p3-catch,p1 的 then 虽然排在第 1 位,但只是返回了一个新的 promise 并将 p1-catch 添加到 micro task 队列,并没有回调 then 的第一个参数,所以 p2-then 赢得 race 。
    rodrick
        5
    rodrick  
    OP
       2021-01-30 16:16:01 +08:00
    @h503mc 是指 p1 还没 reject 的时候 p2 已经 resolve 了么
    @genal 大概明白了
    rodrick
        6
    rodrick  
    OP
       2021-01-30 16:18:41 +08:00
    @faceRollingKB 啊我明白了!确实是在微任务队列里是有先后执行顺序的,我给这茬忘了,非常感谢
    TommyDx
        7
    TommyDx  
       2021-01-30 16:24:40 +08:00
    第二种写法,在 p1 的 reject 还没被 catch 的时候,p2 的 resolve 已经被 new Promise 的 resolve 函数输出了
    cxe2v
        8
    cxe2v  
       2021-01-30 17:29:39 +08:00   ❤️ 1
    4 楼说的很详细了,我说下简化版本的

    第一种写法,是同时将 resolve 和 reject 添加到了 微任务 队列
    第二种写法,只是将 resolve 先添加到了微任务队列,然后再依次添加了 catch 到微任务

    那么第二种写法在执行的时候,肯定是谁先 resolve 谁就赢了,因为 reject 的那个 catch 微任务是排在所有 resolve 的后面的
    Sparetire
        9
    Sparetire  
       2021-01-30 17:30:11 +08:00 via Android
    第一种写法一个 tick,第二种写法两个 tick
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4386 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 10:14 · PVG 18:14 · LAX 02:14 · JFK 05:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.