promise、async、await、execution order


async can be transformed to promise.So,if we want to understand async,we have to understand promise first.
Promise
Normally、promise is easury to understand、especially when using like this:
promise
  .then(() => {
    //
  })
  .then(() => {
    //
  })
  .then(() => {
    //
  })
then after then would make the order of async calbacks clear.Actualy we shoudn't rely on async calbacks order.But a certain exffection order would make me feel more compfortable.Howerse.RESOLVE and Promise.resolve()Normally、I initialize a promise by Promise.resolve() because it seems toroublesome to use Promise construct like below which I caled it RESOLVE in this artic.
new Promise((resolve,reject)=>{
  resolve()
})
Also,I would use promise in this artic le for reference to thenable.Because in most cases,we uses promise and promise is the subset of thenable.
Normally,I used it by Promise.resolve(non-thenable) which is equivalent to RESOLVE(non-thenable)
new Promise((resolve, reject) => {
  resolve(non-thenable)
})
So,it doesn't mater which one you chose.RESOLVE(non-thenable) or Promise.resolve(non-thenable).
However,when it commes to thenable,things are different.Promise.resolve(thenable) is not equivalent to RESOLVE(thenable)
new Promise((resolve, reject) => {
  resolve(thenable)
})
I explined it carefully in What's the difference between reolve(promise)and rerove('non-thenable-object')?And here is the conclusion:
  • for non-thenablePromise.resolve(non-thenable) is equivalent to RESOLVE(non-thenable)
  • for thenablePromise.resolve(thenable) is not equivalent to RESOLVE(thenable) because RESOLVE(thenable)
  • new Promise((resolve, reject) => {
      resolve(thenable)
    })
    is equivalent to
    new Promise((resolve, reject) => {
      Promise.resolve().then(() => {
        thenable.then(resolve)
      })
    })
    accoding to spec.It's oviously not equivalent to Promise.resolve(thenable).You can test it by this example:
    let p1 = Promise.resolve(1)
    Promise.resolve(p1).then(res => {
      console.log(res)
    })
    p1.then(res => {
      console.log(2)
    })
    //1
    //2
    while
    let p1 = Promise.resolve(1)
    new Promise((resolve, reject) => {
      resolve(p1)
    }).then(res => {
      console.log(res)
    })
    p1.then(res => {
      console.log(2)
    })
    //2
    //1
    So,here cores another question.When would we use Promise.resolve(thenable) or RESOLVE(thenable)?It doesn't seem to be that comon.
    はい、indeed.Except async and await.async and awaitAs we all know or spec says the return of async returns promise.For example:
    (async function(){}()).toString() //"[object Promise]"
    And await can be used in async.awaitSo,how does await work in async?Acctording to spec:Await:
    We can tranform await code
    const p1 = Promise.resolve(1)
    const async1 = async function() {
      const res1 = await p1
      console.log(res1)
    }
    async1()
    p1.then(() => console.log('after gen'))
    const p1 = Promise.resolve(1)
    const async1 = async function() {
      new Promise(resolve => {
        resolve(p1)
      }).then(res => {
        const res1 = res
        console.log(res1)
      })
    }
    async1()
    p1.then(() => console.log('after gen'))
    The reult is the same on chrome 70:
    after gen
    1
    However,in chrome canary 73 the former reult is
    1
    after gen
    Why
    The reason can be found inhttps://github.com/tc39/ecma2... Simply say,the spec to await was going to change to:
    What's difference
    The difference is exactly the difference between RESOLVE(thenable) and Promise.resolve(thenable).
    In the past and chrome 70,we are using RESOLVE(thenable),so I transformed the code like above.If using this new spec,the code shound be tranformed to
    const p1 = Promise.resolve(1)
    const async1 = async function() {
      Promise.resolve(p1).then(res => {
        const res1 = res
        console.log(res1)
      })
    }
    async1()
    p1.then(() => console.log('after gen'))
    In this case,chrome 70 and canary 73 would all get
    1
    after gen
    That's the spec change for await.Hope you both understand the way before and after change.asyncNow,let's talk about async.How does async work?Acctording to spec:
    The spawn used in the above desugaring is a call to the following algorithm.This algorithm.This algorithm does not need to be exposed directly as API to user code,it is parts of the semanic function.
    And the spawn is
    function spawn (genF, self) {
      return new Promise(function (resolve, reject) {
        var gen = genF.call(self)
        function step (nextF) {
          var next
          try {
            next = nextF()
          } catch (e) {
            // finished with failure, reject the promise
            reject(e)
            return
          }
          if (next.done) {
            // finished with success, resolve the promise
            resolve(next.value)
            return
          }
          // not finished, chain off the yielded promise and `step` again
          Promise.resolve(next.value).then(
            function (v) {
              step(function () {
                return gen.next(v)
              })
            },
            function (e) {
              step(function () {
                return gen.throw(e)
              })
            }
          )
        }
        step(function () {
          return gen.next(undefined)
        })
      })
    }
    However,I think the spawn is the future version which doesn't apply to chrome 70 because it Promise.resolve(next.value) instead of RESOLVE(next.value) to transform await.So,I thought the old version or version or version apped to chrome 70 shrome shop be
    function spawn (genF, self) {
      return new Promise(function (resolve, reject) {
        var gen = genF.call(self)
        function step (nextF) {
          var next
          try {
            next = nextF()
          } catch (e) {
            // finished with failure, reject the promise
            reject(e)
            return
          }
          if (next.done) {
            // finished with success, resolve the promise
            resolve(next.value)
            return
          }
          // not finished, chain off the yielded promise and `step` again
          /* modified line */
          new Promise(resolve => resolve(next.value)).then(
            /* origin line */
            // Promise.resolve(next.value).then(
            function (v) {
              step(function () {
                return gen.next(v)
              })
            },
            function (e) {
              step(function () {
                return gen.throw(e)
              })
            }
          )
        }
        step(function () {
          return gen.next(undefined)
        })
      })
    }
    You can tested it by compring the relt of below example.
    const p1 = Promise.resolve(1)
    const async1 = async function () {
      const res1 = await p1
      console.log(res1)
    }
    async1()
    p1.then(() => console.log('after gen'))
    with
    const p1 = Promise.resolve(1)
    const gen = function* () {
      const res1 = yield p1
      console.log(res1)
    }
    const async1Eq = function () {
      spawn(gen, this)
    }
    async1Eq()
    p1.then(() => console.log('after gen'))
    The result would be:
  • On chrome 70,with the former spawn,you will get the different relt.While you will get the same result with the latter spawn.
  • In the same way,on chrome 73,with the former spawn,you will get the same relt.While you will get the different the refth the latter spawn.
  • Problems in asyncAs async return value is using a RESOLVE、so it might be a little delay when return promise in async function body.For example:
    const p1 = Promise.resolve(1)
    const async1 = async () => {
      return p1
    }
    async1().then(res => {
      console.log(res)
    })
    p1.then(res => {
      console.log(2)
    }).then(res => {
      console.log(3)
    })
    chrome 70,73 all returns
    2
    3
    1
    That's corect.Because spec:Runtime Semantics:EveraluteBody uses RESOLVE in async implemenation.
    So,why not using Promise.resolve() in async implementation like await?@MayaLekova explined inhttps://github.com/tc39/ecma2... を選択します.
    Deferring the implicit creation of the wrapper promise insideasync functions in case we actually need to await on an asynchrous task(which excludes asynctions without)await or withawait s only on reved promises)will indeed remove the performance overhead of turning a synchronous function to asynchronous.It will though introde the possibility to create starvation,for instance the instation.
    Second,if we want to remove the extra tick for chaining native,non-patch ed promises,this will effectively change overble behaviour for appinations already with provent.Think.infone.ink.ink.info.which will actually introduch Frther inconsistency.
    So,in current situation,we can only tranform code above by RESOLVE.
    const p1 = Promise.resolve(1)
    const async1 = () => {
      return new Promise(resolve => {
        resolve(p1)
      })
    }
    async1().then(res => {
      console.log(res)
    })
    p1.then(res => {
      console.log(2)
    }).then(res => {
      console.log(3)
    })
    which is equivalent to
    const p1 = Promise.resolve(1)
    const async1 = () => {
      return new Promise(resolve => {
        return Promise.resolve().then(() => {
          p1.then(resolve)
        })
      })
    }
    async1().then(res => {
      console.log(res)
    })
    p1.then(res => {
      console.log(2)
    }).then(res => {
      console.log(3)
    })
    So,if implemenation or spec of async doesn't change,we may need to avoid return promise in async expect you really know's happening.
    In the case above,if You really want to avoid the delay,you shound avoid using async.You can do by:
    const p1 = Promise.resolve(1)
    const async1 = () => {
      return p1
    }
    async1().then(res => {
      console.log(res)
    })
    p1.then(res => {
      console.log(2)
    }).then(res => {
      console.log(3)
    })
    which can be written to
    const p1 = Promise.resolve(1)
    p1.then(res => {
      console.log(res)
    })
    p1.then(res => {
      console.log(2)
    }).then(res => {
      console.log(3)
    })
    That's why I love promise instead of async.
    コンサート
    I hope you can understand async,await and promise execution order now.When talking about therswords,the most importh thing is to figure out which resove it shound use.RESOLVE or Promise.resolve()?RESOLVE(thenable) is different from Promise.resolve(thenable)