Promise链式执行顺序

126 阅读4分钟

promise 定义

Promise:promise 是⼀个拥有 then ⽅法的对象或函数,其⾏为符合本规范。 具有 then ⽅法(thenable):是⼀个定义了 then ⽅法的对象或函数; 值(value):指任何 JavaScript 的合法值(包括 undefined , thenable 和 promise); 异常(exception):是使⽤ throw 语句抛出的⼀个值。 原因(reason):表示⼀个 promise 的拒绝原因

.如果onFulfilled是一个函数,且有返回值,则返回值可以继续传递给后续的then
.如果onFulfilled是一个函数,但没有返回值(相当于return undefined),则后续then中的入参为undefined
.如果onFulfilled不是函数,则忽略当前then,将参数直接传递给后续的then
如果 x 有 then ⽅法且看上去像⼀个 Promise ,解决程序即尝试使 promise 接受 x 的状态;否则其 ⽤ x 的值来执⾏ promise 。 如果 promise 和 x 指向同⼀对象,以 TypeError 为据因拒绝执⾏ promise 如果 x 为 promise 如果 x 处于等待态, promise 需保持为等待态直⾄ x 被执⾏或拒绝 如果 x 处于执⾏态,⽤相同的值执⾏ promise 如果 x 处于拒绝态,⽤相同的据因拒绝 promise
.如果 x 为 Object 或 function(不常⻅) ⾸先尝试执⾏ x.then 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise 如果 then 是函数,将 x 作为函数的作⽤域 this 调⽤。传递两个回调函数作为参数,第⼀ 个参数叫做 resolvePromise ,第⼆个参数叫做 rejectPromise : 如果 resolvePromise 以值 y 为参数被调⽤,则运⾏ [[Resolve]](promise, y) 如果 rejectPromise 以据因 r 为参数被调⽤,则以据因 r 拒绝 promise promise.then(function(x) { console.log('会执⾏这个函数,同时传⼊ x 变量的值', x); });
.如果 resolvePromise 和 rejectPromise 均被调⽤,或者被同⼀参数调⽤了多次,则优先 采⽤⾸次调⽤并忽略其他的调⽤ 如果调⽤ then ⽅法抛出了异常 e 如果 resolvePromise 或 rejectPromise 已经被调⽤,则忽略 否则以 e 为据因拒绝 promise 如果 then 不为函数,以 x 为参数将 promise 变为已完成状态 如果 x 不为对象或者函数,以 x 为参数将 promise 变为已完成状态(重要且常⻅)

promise 解决过程

Promise 解决过程是⼀个抽象的操作,其需输⼊⼀个 promise 和⼀个值,我们表示为 [[Resolve]] (promise, x) (这句话的意思就是把 promise resolve 了,同时传⼊ x 作为值)
如果 x 有 then ⽅法且看上去像⼀个 Promise ,解决程序即尝试使 promise 接受 x 的状态;否则其 ⽤ x 的值来执⾏ promise 。
如果 promise 和 x 指向同⼀对象,以 TypeError 为据因拒绝执⾏ promise
如果 x 为 promise
如果 x 处于等待态, promise 需保持为等待态直⾄ x 被执⾏或拒绝
如果 x 处于执⾏态,⽤相同的值执⾏ promise
如果 x 处于拒绝态,⽤相同的据因拒绝 promise

容易忽略的两个点

1、promise异步执行是在 .then后.then前还是同步执行
2、如果没有return,promise会成为一个副作用,然后把undefined传递给后续的then, then并不会等待这个promise!

两个例题 例题1

const log = console.log
new Promise((res, rej) => {
  log(1)
  res()
})
  .then(()=>{
    log(2)
    return new Promise((res, rej)=>{
      log(3)
      res()
    })
        .then(()=>{log(4)})
        .then(()=>{log(5)})
  })
  .then(() => {log(6)})

// 1 2 3 4 5 6 例题2

const log = console.log
new Promise((res, rej) => {
  log(1)
  res()
})
  .then(() => {
    log(2)
    new Promise((res, rej)=>{
      log(3)
      res()
    })
        .then(()=>{log(4)})
        .then(()=>{log(5)})
  })
  .then(() => {
    log(6)
  })

// 1 2 3 4 6 5 这两段代码的区别在于对Promise对象的使用方式和then方法的调用时机不同。

第一段代码使用了链式调用,即在第一个Promise的then方法中返回了一个undefined,然后继续调用后续的then方法。在第一个Promise的resolve方法被调用之后,会执行第一个then方法的回调函数,即打印2,然后创建一个新的Promise对象,并在其then方法中连续调用了两个then方法,分别打印4和5。最后,执行第一个Promise的then方法的回调函数,即打印6。

第二段代码执行顺序 123645 进入第一个promise第一个then(微任务队列1)后进入第二个promise,第二个.then进入微任务队列,第二个promise没有retrun是同步执行,第二个promise执行成功后立即执行4,子promise第二个then微任务队列(微任务队列3)挂起。至此第一个.then微任务任务执行完成,执行第二个微任务队(微任务队列2)列 log(6),微任务先进先出原则 先执行微任务队列2 再执行微任务队列3

因此,两段代码的区别在于第一个Promise对象的then方法的返回值不同(一个返回undefined,一个返回一个新的Promise对象),以及第一个Promise对象的then方法的调用时机不同(第一个代码是在第一个Promise的回调函数中调用的,第二个代码是直接在Promise对象上调用的)