最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 异步编程

    正文概述 掘金(康小源)   2020-11-27   440

    一. 概述

    1. 异步模式

    • 异步模式的 api 不会等待这个任务的结束才开始下一个任务
    • 对于耗时操作(异步操作)开启过后就立即往后执行下一个任务
    • 后续逻辑一般会通过回调函数的方式定义

    2. 回调函数

    • 所有异步编程方案的根基
    • 由调用者定义,交给执行者执行的函数

    3. Promise

    • CommonJs 社区提出了 Promise 规范

    • 在 ECMA 2015 中被标准化,成为语言规范

    • Promise 实际是一个对象,用来表示一个异步任务在执行过后是成功还是失败,状态一旦确定,不会改变

    • 状态

      • pending 等待
      • fulfilled 成功 -> onFulfilled
      • rejected 失败 -> onRejected
    • 基本用法

      const promise = new Promise((resolve, reject) => {
        // resolve(100) // 成功
        reject(new Error('promise rejected')) // 失败
      })
        
      promise.then(res => {
        console.log(res)
      }, err => {
        console.log(err)
      })
      
    • Promise 使用案例

      function ajax(url) {
        return new Promise((resolve, reject) => {
          const xhr = new XMLHttpRequest()
          xhr.open('GET', url)
          xhr.responseType = 'json'
          xhr.onload = function () {
            if (this.status === 200) {
              resolve(this.response)
            } else {
              reject(new Error(this.statusText))
            }
          }
          xhr.send()
        })
      }
      
    • Promise 链视调用

      • Promise 对象的 then 方法会返回一个权限的 Promise 对象
      • 后面的 then 方法就是在为上一个 then 方法返回的 Promise 注册回调
      • 前面的 then 方法中回调函数的返回值会作为后面 then 方法回调的参数
      • 如果回调返回的是 Promise,后面的 then 方法的回调会等待它的结束
      const { resolve } = require("path")
        
      const promise = new Promise((resolve, reject) => {
        resolve(1)
      })
        
      promise.then(res => {
        console.log(res)
        return new Promise(resolve => {
          resolve(2)
        })
      }).then(res => {
        console.log(res)
      })
      
    • Promise 静态方法

      • Promise.resolve() 返回一个状态为 fulfilled 的 Promise 对象
      • Promise.reject() 返回一个状态为 rejected 的 Promise 对象
      • Promise.all() 并行执行,等待所有任务结束才结束,需要一个数组作为参数,数组中存放通过 promise 实现的异步任务,返回一个 Promise 对象
      • Promise.race() 并行执行,等待其中一个任务结束就结束,需要一个数组作为参数,数组中存放通过 promise 实现的异步任务,返回一个 Promise 对象
    • 宏任务和微任务

      • 宏任务:回调队列中的任务
      • 微任务:宏任务执行过程中可以的一些额外需求,Promise 的回调作为微任务执行
        • 常见微任务:
          • Promise 回调
          • MutationObserver
          • process.nextTick()

    二. Promise 源码

    1. 须知

    • Promise 是一个类,在执行这个类的时候需要传递一个执行器,执行器会立即执行
    • Promise 中有三种状态
      • 成功 fulfilled
      • 失败 rejected
      • 等待 pending
        • pending 可以转变为 fulfilled
        • pending 可以转变为 rejected
        • 一旦状态改变就不能更改
    • resolve 和 reject 函数是用来更改状态
      • resolve 是把状态变为成功
      • reject 是把状态变为失败
    • then 方法内部就是判断状态,如果状态为成功,调用成功回调函数,如果状态失败,调用失败回调函数,then 方法是被定义在原型对象中
    • then 成功回调有一个参数,表示成功之后的值,then 失败回调有一个参数,表示失败之后的错误
    • 同一个 promise 对象下面的 then 方法是可以被调用多次的
    • then 方法是可以被链式调用的, 后面 then 方法的回调函数拿到值的是上一个 then 方法的回调函数的返回值

    2. 模拟 Promise

    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    
    class MyPromise {
      constructor(executor) {
        try {
          executor(this.resolve, this.reject)
        } catch (err) {
          this.reject(err)
        }
      }
    
      status = PENDING
      value = undefined
      error = undefined
      successCallback = []
      failCallback = []
    
      resolve = value => {
        if (this.status !== PENDING) {
          return
        }
        this.status = FULFILLED
        this.value = value
        while (this.successCallback.length) {
          this.successCallback.shift()()
        }
      }
    
      reject = error => {
        if (this.status !== PENDING) {
          return
        }
        this.status = REJECTED
        this.error = error
        while (this.failCallback.length) {
          this.failCallback.shift()()
        }
      }
    
      then(successCallback, failCallback) {
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : error => { throw error }
        const promise2 = new MyPromise((resolve, reject) => {
          if (this.status === FULFILLED) {
            setTimeout(() => {
              try {
                const x = successCallback(this.value)
                resolvePromise(promise2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            }, 0)
          } else if (this.status === REJECTED) {
            setTimeout(() => {
              try {
                const x = failCallback(this.error)
                resolvePromise(promise2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            }, 0)
          } else {
            this.successCallback.push(() => {
              setTimeout(() => {
                try {
                  const x = successCallback(this.value)
                  resolvePromise(promise2, x, resolve, reject)
                } catch (error) {
                  reject(error)
                }
              }, 0)
            })
            this.failCallback.push(() => {
              setTimeout(() => {
                try {
                  const x = failCallback(this.error)
                  resolvePromise(promise2, x, resolve, reject)
                } catch (error) {
                  reject(error)
                }
              }, 0)
            })
          }
        })
        return promise2
      }
    
      finally(callback) {
        return this.then(value => {
          return MyPromise.resolve(callback()).then(() => value)
        }, error => {
          return MyPromise.reject(callback()).then(undefined, () => { throw error })
        })
      }
    
      catch(failCallback) {
        return this.then(undefined, failCallback)
      }
    
      static all(array) {
        let result = []
        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), error => reject(error))
            } else {
              addData(i, current)
            }
          }
        })
      }
    
      static resolve(value) {
        if (value instanceof MyPromise) {
          return value
        }
        return new MyPromise(resolve => resolve(value))
      }
    
      static reject(error) {
        if (error instanceof MyPromise) {
          return error
        }
        return new MyPromise(undefined, reject => reject(error))
      }
    }
    
    function resolvePromise(promise2, x, resolve, reject) {
      if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
      }
      if (x instanceof MyPromise) {
        x.then(resolve, reject)
      } else {
        resolve(X)
      }
    }
    
    module.exports = MyPromise
    

    起源地下载网 » 异步编程

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元