异步编程

148 阅读5分钟

事件循环

每个代理都是由事件循环驱动,事件循环负责收集事件,对任务进行排队以便在合适的的时间进行回调,调用它执行所有处于等待中的任务,然后是微任务.然后再下一次循环结束前执行一些必要的渲染和绘制操作(EventLoop是一种事件循环机制,不断去轮询一些队列,从中找出需要执行的任务并按照顺序执行)

消息队列

  • 是用来存放宏任务的队列,比如定时器时间到了,定时间内传入的方法引用会存到该队列,ajax 回调之后的执行方法也会存到该队列
  • 一开始整个脚本作为一个宏任务执行。执行过程中同步代码直接执行,宏任务等待时间到达或者成功后,将方法的回调放入宏任务队列中,微任务进入微任务队列。当前主线程的宏任务执行完出队,检查并清空微任务队列。接着执行浏览器 UI 线程的渲染工作,检查web worker 任务,有则执行。然后再取出一个宏任务执行。以此循环...

宏任务

可以理解为每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行), 浏览器为了让JS内部宏任务与DOM操作能够有序的执行,会在一个宏任务执行结束后,在下一个宏任务执行开始前,对页面进行重新渲染
宏任务包含:script(整体代码)、setTimeout、setInterval、I/O、UI 交互事件、MessageChannel等

微任务

可以理解是在当前任务执行结束后需要立即执行的任务。也就是说,在当前任务后,在渲染之前,执行清空微任务,所以它的响应速度相比宏任务会更快,因为无需等待 UI 渲染
微任务包含:Promise.then、MutaionObserver、process.nextTick(Node.js 环境)等

整理

  async function async1() {
    console.log('A')
    async2()  //加await前缀结果都一样
    console.log('B')
  }
  async function async2() {
    console.log('C')
  }
  async1()
  console.log('D')
  /*
    1 A,C,B,D await等待同步任务执行完在执行后面代码
    2 微任务可以派生新的微任务
    3 新的微任务会在下一个任务开始之前和当前事件循环结束之前只执行完所有的微任务
  */

 new Promise((resolve, reject) => {
   console.log(111)
   resolve(222)
  }).then(res => {
     console.log(res) //222
  }).then(res => {
     console.log(res) //undefined
  })
  /*
    1 在创建promise实例的时候函数立即执行,第一个then的状态取决于回调函数的resolve或reject返回结果
    2 如果实例的state状态改变,下一个then接收的参数依赖上一个then回调返回结果
    3 默认返回undefined,返回普通值相当于执行resolve回调
  */

 async function t2() {
   let a = await new Promise(resolve => {})
   console.log(a)
 }
 t2()
 //不执行,此时的a的状态为pedding,await执行a状态改变后resolve或reject的值
 
  new Promise((resolve, reject) => {
      console.log(1)
  }).then(res => {
      console.log(2)
  })
//2不执行state的状态没有改变,then回调都不会执行

async function t4() {
    let a = await new Promise(resolve => {
    resolve('hello')
  }).then(() => {
    return 'lala'
  })
    console.log(a) //lala
}
t4() 
//promise的then回调都会返回一个新的promise实例,await会跟一个最后返回的promise对象

async function t5() {
   let a = await fn().then(res => {
   return res
})
   console.log(a)
}
async function fn() {
   await new Promise(resolve => {
     resolve('lagou')
   })
}
t5() 
//返回undefined fn()没有返回promise对象 await没跟promise对象默认返回undefined

let promise = new Promise((resolve, reject) => {
    setTimeout(() => {
       resolve(111)
    }, 2000)
})
promise.then(res => {
   console.log(res)
   return 222
}).then(res => {
    console.log(res)
})
//等待2s后打印111,222
const t1 = setTimeout(() => {
  console.log(1)
}, 3000)
const t2 = setTimeout(() => {
  console.log(2)
  const t3 = setTimeout(() => {
     console.log(3)
   }, 1000)
 }, 1000)
 /*
  1 执行结果2,3,1 t1和t2为同一个进程两个异步任务
  2 t2先执行,t2执行完后t1还剩下2s执行,t3进入第二轮的异步
  3 任务队列1s后执行,t3优于t1执行
 */

模拟promise实现

  1. Promise就是一个class,在执行这个class会传递一个执行器(executor),执行器会立即执行
  2. Promise三种状态pending\fulfilled\rejected,状态只能从 pending=>fulfilled,pending=>rejected 一旦状态改变就不可更改
  3. resolve和rejected是用来更改promise状态的
  4. then回调接收成功或失败的值 resolve(value)或reject(reason)
  5. then方法返回promise对象,下一个then方法接收的值依赖上一个then方法返回的值,默认不写返回undefined
  6. all方法参数是数组,只要有一个失败promise返回失败结果,都是成功状态会按照参数顺序返回相应的结果(返回结果是promise实例)
  7. resolve方法返回promise实例,普通值在内部会自动转换成promise实例
  8. finally不管成功或失败都会执行,链式调用
     const PENDING = 'pending'
     const FULFILLED = 'fulfilled'
     const REJECTED = 'rejected'
     class MyPromise {
        constructor(executor) {
          try {
            executor(this.resolve, this.reject)
          } catch (e) {
            this.reject(e)
          }
        }
        //默认状态是PENDING
        status = PENDING
        value = ''
        reason = ''
        //实现promise的then链式调用
        successCallBack = []
        failCallBack = []
        resolve = value => {
          //如果状态不是等待阻止程序向下执行
          if (this.status !== PENDING) return
          this.status = FULFILLED
          this.value = value
          //this.successCallBack存储数据[fn1,fn2,fn3,fn4]都是函数组成的数组
          while (this.successCallBack.length) {
            this.successCallBack.shift()()
          }
        }
        reject = reason => {
          if (this.status !== PENDING) return
          this.status = REJECTED
          this.reason = reason
          while (this.failCallBack.length) {
            this.failCallBack.shift()()
          }
        }
        then(successCallBack, failCallback) {
          //实现then方法默认参数传递
          successCallBack = successCallBack ? successCallBack : value => value
          failCallback = failCallback
            ? failCallback
            : reason => {
                throw reason
              }
          //每一个then方法返回promise实例
          let promise = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
              //异步代码确保获取promise这个参数
              setTimeout(() => {
                try {
                  //判断x的值是普通值还是promise对象
                  //普通值就直接resolve
                  //如果是promise对象,查看promise对象返回结果
                  //根据返回结果用resolve或reject
                  let x = successCallBack(this.value)
                  //公用函数处理x
                  resolvePromise(promise, x, resolve, reject)
                } catch (e) {
                  reject(e)
                }
              }, 0)
            } else if (this.status === REJECTED) {
              setTimeout(() => {
                try {
                  let x = failCallback(this.reason)
                  resolvePromise(promise, x, resolve, reject)
                } catch (e) {
                  reject(e)
                }
              }, 0)
            } else {
              this.successCallBack.push(() => {
                setTimeout(() => {
                  try {
                    let x = successCallBack(this.value)
                    resolvePromise(promise, x, resolve, reject)
                  } catch (e) {
                    reject(e)
                  }
                }, 0)
              })
              this.failCallBack.push(() => {
                setTimeout(() => {
                  try {
                    let x = failCallback(this.reason)
                    resolvePromise(promise, x, resolve, reject)
                  } catch (e) {
                    reject(e)
                  }
                }, 0)
              })
            }
          })
          return promise
        }
        catch(failCallback) {
          return this.then(undefined, failCallback)
        }
        finally(callback) {
          return this.then(
            value => {
              return MyPromise.resolve(callback()).then(() => value)
            },
            reason => {
              return MyPromise.resolve(callback()).then(() => {
                throw reason
              })
            }
          )
        }
        static resolve(value) {
          if (value instanceof MyPromise) return value
          return new MyPromise(resolve => resolve(value))
        }
        //all方法接收的参数是数组
        static all(array) {
          let result = []
          //确保all方法里面的参数全部获取到
          let index = 0
          return new MyPromise((resolve, reject) => {
            function addData(key, value) {
              result[key] = value
              index++
              if (index === array.length) {
                resolve(result)
              }
            }
            for (let i = 0; i < array.length; i++) {
              const current = array[i]
              if (current instanceof MyPromise) {
                current.then(
                  value => addData(i, value),
                  reason => reject(reason)
                )
              } else {
                addData(i, array[i])
              }
            }
          })
        }
      }
      function resolvePromise(promise, x, resolve, reject) {
        if (promise === x) {
          reject(new TypeError('Circular reference error'))
        }
        //x是promise实例
        else if (x instanceof MyPromise) {
          x.then(resolve, reject)
        } else {
          resolve(x)
        }
      }