关于promise和async的深入理解

354 阅读3分钟
  1. 本质原因是JS需要交互,需要引入时间的概念。

  2. sync=同步,async=不同步,字面意思跟实际执行情况正好相反。如果没有异步执行,则按照JS的代码一条一条line by line同步执行,执行的逻辑是event loop,即每条代码执行过程中:如果在main thread上的代码则逐步执行,同步执行顺序参考: developer.mozilla.org/en-US/docs/… 优先级**(stack/script,microtask/promise,task/webapi)**

  1. 既然JS正常是同步执行,为何要引入异步的概念?异步的引入是为了“同步”操作流程!

如果要在执行中引入先后的顺序怎么办?比如先获取地理位置再才能计算距离长度。如果同步执行,则会发生错乱。比如地理位置api还没有返回回来,则开始了计算,会出现undefined的错误。

let location=getLoaction(api){
    fetch(api);
}
//calCulateDistance
let distance= (location+32)*232/45;
console.log(distance);

那么该怎么“同步”这些先后顺序的操作呢?即通过人工控制执行顺序。

#一. 以CallBack方法引入先后顺序#

fetch(api,(err,location)={
    if(location) {
      let distance= (location+32)*232/45;
      console.log(distance);
    };
})

问题是:复杂的逻辑,会引起callback hell,而且把callback函数交由第三方fetch不好。

#二. 以Promise方法引入先后顺序(需要改写CallBack)

getLoaction ()=>{
 return new Promise((resolve, reject) =>{  
    fetch(api,(err,location)={
    if(location) {
     resolve(location)
    }else{
     reject(err)
    };
})
})

需要仔细理解的是:代码行碰到promise的时候即开始执行(按照原生的自带的顺序执行stack/microtask/task),轮到microtask的时候,promise已经开始执行,promise是一个已经存在的对象object,这个对象状态在按照内部逻辑更新而已,即pending->fullfilled(reject/resolve)。这个对象是一直存在的。这个对象的内部有一些监听器,then/catch,当对象状态变化时,则触发onThen监听器,其实也是调用我们传入的CallBack函数而已!这样说来promise本质是方法一CallBack的不同写法而已!!

需要注意的细节是:

  1. Promise的状态在microtask完成后才能改变,如果要获取改变后的值,则需要then,不然promise只是一个带状态的object

  1. 如果修改一下,则发现如下结果,因为microtask运行按照queue来的

3.关于then(其实就是CallBack函数,也叫then handler)返回的问题

A.如果then返回return了ThenReturnedValue,则相当于返回一个Promise.resolve(),这个promise以供下一个then来使用consume

B.如果then返回了reject或者throw error,则Promise.reject()

C.如果then返回一个新的Promise,叫NewPromise,则NewPromise

then因为是CallBack,error first callback(其实是error second callback),所以形式是:.then( resolveCallBackFun,rejectCallBackFun)

#三. 以Async Await方法引入先后顺序(改写Promise)

  1. Async其实是promise+generator(本质是promise), await就是相当于把promise .then了一下(当然error是通过try catch获取,类似then/catch),跟promise区别是会把后面的全部暂停住,相当于wrap到then里面。如图
function resolveAfter2Seconds() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved');
    }, 1000);
  });
}

async function asyncCall() {
  console.log('calling');
  var result = await resolveAfter2Seconds();
  console.log(result);
  console.log('ending');
 }


function promiseCall2() {
  console.log('calling');
  resolveAfter2Seconds().then((result)=>{
     console.log(result);
   }); 
  console.log('ending');
}

asyncCall();//会hold住所有后面的;整个执行顺序还是正常同步流程stack->microtask->task
> "calling"
> "resolved"
> "ending"

promiseCall2(); //只会hold then里面的;整个执行顺序还是正常同步流程stack->microtask->task
> "calling"
> "ending"
> "resolved"

2.关于async函数func返回的问题, 相当于.then callback, async函数返回也:

A.如果返回value,则async返回Promise.resolve()

B.如果返回NewPromise,则NewPromise

C.如果返回Error,则Promise.reject(),可以通过后续的try/catch捕获

D.如果没有return,则返回Promise.resolve(NULL)

3.async的小技巧IIF

(async () => {
    try {
        var text = await myPromise();
         
    } catch (e) {
       
    }
})();

上面的论证被Mozilla再次证明!

重要文献:

jakearchibald.com/2015/tasks-…

developer.mozilla.org/en-US/docs/…

developer.mozilla.org/en-US/docs/…

developer.mozilla.org/en-US/docs/…