Promise,async,await

一.Promise与then

Promise是解决异步的一种手段但其本身不是异步的,then是异步调用的,简而言之catch方法也是异步的。

let promise = new Promise((resolve,reject)=>{
  console.log('exactor')
  resolve('实现承诺')
})
promise.then((res)=>{ 
  console.log(res)  
  return new Promise((resolve,reject)=>{  // then里面还可以返回Promise
    console.log('3')
    resolve('成功')
  })
},(err)=>{
  console.log(err)
}).then((res)=>{
  console.log(res)
})
console.log('1')
console.log('2')
复制代码

image.png

首先由于Promise本身是同步的所以 console.log(‘exactor’)属于同步代码,但是resolve的结果被then接收,then是异步执行的,所以then这个方法会等所有同步的代码执行完毕后再执行。

二.Promise(A+)与浏览器中Promise的差异

直观的解释在于:在Promise.resolve()这步操作的时候,浏览器运行的Promise比Promise(A+)这个库直接运行的时候多了一个微任务即将Promise.resolve()压入到微任务队列中。这也就是Promise/A+实现和Promise浏览器实现的本质区别

Promise.resolve().then(() => {
  console.log(0);
  // return Promise.resolve(4); 
  return new Promise((resolve,reject)=>{
    resolve(4)    
  })            
}).then((res) => {
  console.log(res)
})
Promise.resolve().then(() => {
  console.log(1);
}).then((res) => {
  console.log(2);
}).then(() => {
  console.log(3);
}).then(() => {
  console.log(5);
}).then(() =>{
  console.log(6);
})

// 0 1 2 3 4 5 6 
复制代码

首先执行两个Promise.resolve()并注册两个then

执行第一个注册的then并输出0 并且将new Promise中resolve的结果放到微任务队列中

此时微任务队列的对头是第二个then 所以执行第二 输出1 并注册第三个then即将其放入微任务队列中

此时微任务队列的对头是第一个then中resolve的结果 并注册then 发现没有then 则return结束

此时微任务对头是第三个then 所以执行第三个注册的then输出2 并注册第四个then

然后注册上述reuturn结束后的第五个then

此时微任务队列的对头是第四个then 所以输出3 并注册第六个then

此时微任务队列的对头的是第五个then 所以输出4 并注册第七个then 依次进行下去

new Promise((resolve, reject) => {
  console.log('then->1');
  resolve();
})
  .then(() => {
    console.log('then->2');
    new Promise((resolve, reject) => {
      console.log('then->3');
      resolve();
    })
      .then(() => {
        console.log('then->4');
        return Promise.resolve();
      })
      .then(() => {
        console.log('then->5');
      })
  })
  .then(() => {
    console.log('then->6');
  })
  .then(() => {
    console.log('then->7');
  })
  .then(()=>{
    console.log('then->8')
  })
复制代码

首先执行then->1输出then->1 并注册then->2

此时微任务对头是then->2 输出then->2 且执行同步代码 输出then->3

注册then->4以及then->6

此时微任务的对头是then->4 执行then->4 输出then->4 并且将Promise.resolve输出的结果压入微任务队列

此时的微任务对头是then->6 输出then->6 并注册then->7

此时微任务的对头是resolve的结果 并注册then 但发现没有 则return返回的结果

**此时微任务的对头是then->7 输出then->7 并注册then->8 **

**注册then->5 **

此时微任务还剩then->8 then->5 所以依次执行

所以输出的结果是 1 2 3 4 6 7 8 5

三.Promise.resolve源码实现

Promise.resolve = function(value){
  if(value instanceof Promise){
    return value
  }
  return new Promise((resolve)=>{
    resolve(value)
  })
}
复制代码

四.Promise.all源码实现

all方法的原理是所有传入的Promise都必须是fulfilled状态并将其一并返回出去,如果有一个是rejected状态则将这个结果reject出去

function promiseAll(promiseArr){
  if(!Array.isArray(promiseArr)){
    return
  }
  let index=0,result = [];
  return new Promise((resolve,reject)=>{
    promiseArr.forEach((p)=>{
      p.then((value)=>{
        index++;
        result.push(value)
        if(index === promiseArr.length){
          resolve(result)
        }
      },err=>{
        reject(err)
      })
    })
  })
}
复制代码

五.Promise.any源码实现

any方法的原理是只要传入的Promise有一个是fullfilled状态则立即resolve出去否则将所有reject结果收集起来并返回AggregateError

Promise.all = function(promiseArr){
  if(!Array.isArray(promiseArr)){
    return
  }
  let index = 0;
  return new Promise((resolve,reject)=>{
    promiseArr.forEach((p,i)=>{
      p.then(value=>{
        resolve(value)
      },err=>{
        index++;
        if(index === promiseArr.length){
          reject(new AggregateError('All promises were rejected'))
        }
      })
    })
  })
}
复制代码

六.Promise.race源码实现

race总是返回第一个fullfilled或者rejected的结果

Promise.race = function(promiseArr){
  return new Promise((resolve,reject)=>{
    promiseArr.forEach(p=>{
      Promise.resolve(p).then(val=>{
        resolve(val)
      },err=>{
        reject(err)
      })
    })
  })
}
复制代码

七.Promise.allSettled源码实现

allSettled返回的是返回所有传入的Promise的结果即将fullfilled和rejected的结果合并起来返回

Promise.allSettled = function(promiseArr){
  let result = []
  return new Promise((resolve,reject)=>{
    promiseArr.forEach((p,i)=>{
      p.then(val=>{
        result.push({
          status:'fulfilled',
          value:val,
        })
        if(result.length === promiseArr.length){
          resolve(result)
        }
      },err=>{
        result.push({
          status:'rejected',
          value:val,
        })
        if(result.length === promiseArr.length){
          resolve(result)
        }
      })
    })
  })
}
复制代码

八.async await

async await是建立在promise机制之上的,并不能取代其地位!!!

8.1 async

async定义的函数是异步的且返回一个Promise对象

async function fn(){
  return 'promise'
}
console.log(fn())
复制代码

image.png

因为返回的是Promise对象,所以必然是可以调用then方法的。

需要注意的是async关键字定义函数后表示函数内部有异步操作,但是函数本身是同步的。

async function fn(){
  console.log('promise')
}
fn()
console.log('123')
复制代码

这段代码的结果是先输出promise在输出123所以可以看出fn是同步的。这可以与Promise的执行器进行类比,我们知道在执行器内的代码也是同步的,但是执行器执行完毕后返回的是一个Promise对象,这就如同async是同步的,但是执行完毕后返回的也是Promise对象

8.2 await

await的主要作用是用来等待Promise对象的状态变为fullfilled。所以从await的原理上就可以看出await是异步的,它会让当前async函数内部代码运行到await时停止执行(函数暂停执行),因为它需要等待Promise的解决,然后恢复async函数的执行。这样一来就可以达到同步的效果,因为你必须要等待上一个await执行完毕后才能执行下一个异步函数。

async function async1(){
  console.log('async1 start')
  await async2();  
  console.log('async1 end')
}
async function async2(){
  console.log('async2')
}
async1()
console.log('script start')
setTimeout(()=>{
  console.log('setTimeout')  // 宏任务
},0)


new Promise((resolve,reject)=>{
  console.log('promise1')
  resolve()
}).then(()=>{  // 微任务
  console.log('promise2')
})
console.log('script end')
复制代码

首先我们找到同步代码:async1() console.log(“script start”) console.log(“promise1”) console.log(“script end”) 依次执行输出

当运行async1()的时候 输出内部的async1 start 以及 async2()的结果async2

由于await的存在 我们需要等待async2()返回的Promise的状态变为fullfilled或rejected所以会暂停执行后续的代码(将其放入微任务队列中),这就是异步的体现。

然后运行setTimeout将其放入宏任务队列中。

然后运行then方法将其放入微任务队列中。

最后先运行完微任务队列中的代码在执行宏任务队列中的代码,得到输出结果为:

image.png

九.关于EventLoop会在后续更新

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享