异步流程处理

发表于:2018-3-21 15:40

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:行走的柯南    来源:掘金中国

  promise
  promise 可以说是很常用的异步处理方法
  比如我们使用promise封装一个canvas截图的方法
  clip (resolve, reject) {
      // 截屏 获取图片url
      return new Promise((resolve, reject) => {
        html2canvas(document.getElementById('view'), {
          canvas: canvas,
          onrendered: (canvas) => {
            let getImg = canvas.toDataURL('image/png')
            resolve(getImg)
          }
        })
      })
    }
  实现一个简单的promise
  function Promise (executor) {
    let self = this
    self.status = 'pending'
    self.success // 成功的原因
    self.failure // 失败的原因
    // 事件池
    self.resolvePool = []
    self.rejectPool = []
    function resolve (data) {
      if (self.status == 'rejected') return
      self.status = 'resolved'
      self.success = data
      // 执行队列
      self.resolvePool.forEach(function (cb){
        cb(self.success)
      })
    }
    function reject (data) {
      if (self.status == 'resolved') return
      self.status = 'rejected'
      self.failure = data
      // 执行队列
      self.rejectPool.forEach(function (cb){
        cb(self.failure)
      })
    }
    // new一个实例就会立即执行这个promise
    executor(resolve, reject)
  }
  // then
  Promise.prototype.then = function (onFulfilled, onRejected)  {
    let self = this
    let promiseStatus = self.status
    if (promiseStatus == 'resolved') {
      onFulfilled(self.success)
    }
    if (promiseStatus == 'rejected') {
      onRejected(self.failure)
    }
    // 很有可能此时状态为 pending
    if (promiseStatus == 'pending') {
      // 放入事件池中等待执行
      self.resolvePool.push(function () {
        onFulfilled(self.success)
      })
      self.rejectPool.push(function () {
        onRejected(self.failure)
      })
    }
  }
  Iterator
  let target = beIteraor({name: 'mxx', address: 'beijing'}) 
  target.next()
  target.next()
  Iterator 是一个迭代器对象 每次从集合中取出一项 并且跟踪当前序列所在位置
  通过使用next方法 返回一个包含value和done两个属性的对象
  {value: 当前对象成员, done: Boolean}
  Iterator 简易实现
  let target = beIteraor(['mxx', 'beijing'])
  let a = target.next() 
  let b = target.next()
  let c = target.next()
  // { value: 'mxx', done: false } { value: 'beijing', done: false } { value: 'undefined', done: true }
  // 返回一个具有next方法的对象
  function beIteraor(ary) {
    let index = 0
    let len = ary.length
    return {
      next: function () {
        // 调用next方法  返回 {value, done} 并且指针移动位置
        let done =  ~~index == ~~len
        // 如果指针位置移动到末尾 则返回undefined 否则返回当前位置成员
        let value =  done ? 'undefined' : ary[index]
        index++
        return {value, done}
      }
    }
  }
  generator
      generator 函数生成一个迭代器
  <!-- 函数 注: 这里的read函数直接返回文件中内容 -->
  function * getCont () {
    let name = yield 'youchangjing'
    let address = yield 'beijing'
    return name + address
  }
  <!-- 如何执行 -->
  let getC = getCont()
  getC.next() // {value: 'youchangjing', done: false}
  getC.next() // {value: 'beijing' , done: false}
  getC.next() // {value: undefined , done: true}
  可以看到 generator 函数调用和普通函数一样 fn() 即可 但是函数并不会执行 只有当调用next方法 才能执行到第一个状态
  generator 是分段执行的 yield表示暂停执行 next方法恢复函数执行
  目前来说 浏览器对 generator 支持情况还是很不错的
  co
  如果 yield 后面是一个 promise 函数 可以配合co 库来使用
  <!-- read函数  -- 封装的一个简易的promise -->
  function read(dir) {
    return new Promise((resolve, reject) => {
      fs.readFile(dir, 'utf-8', (err, cont) => {
        if (err) reject(err)
        resolve(cont)
      })
    })
  }
  <!-- generator -->
  function * getCont () {
    let name = yield read('name.js')
    let address = yield read('address.js')
    return name + address
  }
  <!-- 配合co库 -->
  co(getCont()).then(function (cont) {
    console.log(cont) 
  })
  简单的CO实现原理
      co 的参数是一个迭代器
      co 返回的是promise 返回的promise 接受 generator 函数的 value
      co 内部可以使 generator 函数 一直执行到 done 为TRUE
  function co(iterator) {
    return new Promise(function (resolve, reject) {
      function next(cont) {
        let {value, done} = iterator.next(cont)
        <!-- value 也是一个promise  -->
        if (done) {
          <!-- 如果 done 为TRUE 则将value 传入 resolve -->
          resolve(value)
        } else {
          <!-- done 为FALSE 则执行其then 方法 用于获取其data传递给 next -->
          value.then(function (data) {
            next(data) 
            <!-- next 递归 -->
          }, reject)
        }
      }
      next()
    })
  }
  async await
  async await 可以看做 co + generator 的语法糖
  虽然co库可以帮我们自行处理generator 但是又要使用yield 又要封装promise 也是有点麻烦 所以转向 ES7 中的 async await
  目前 async await 在Bable, Node 7+ 中被支持
  async function getCont() {
    let people = await read('./file.js')
    let who = await read('./who.js')
    return people + who
  }
  getCont().then((data) => console.log(data))
      async 返回 promise
  await
  await 顾名思义 等待。那他在等待什么呢。 这个取决于await 后面跟着的内容
  await 'mxx'
  <!-- 等待非promise -->
  await IamPromise()
  <!-- 等待 promise -->
  如果 await 等待的不是一个 promise 那么await表达式的运算结果就是 它等到的东西 (其实await会将其转为一个立即resolve的promise对象)
  如果 await 等待的是promise 那么他会阻塞后面的代码 等着Promise 对象 resolve 然后得到其值作为 await表达式的运算结果
  function getRank () {
    return 12345
  }
  async function getType () {
    let name = await read('who.js')
    <!-- read为promise -->
    console.log(name)
    let rank = await getRank()
    <!-- getRank 为普通函数  -->
    console.log(rank)
  }
      如果我们在普通函数中使用await会被阻塞吗
  好吧~~ 直接报错了
  错误捕获
  async 中有两种错误处理方式
  1 可以在 async 函数中 使用try catch
  async 中对try catch方法做了处理 使其可以捕获异步的错误
  async function () {
    try {
    } catch (e) {
      console.log(e)
    }
  }
  2 在then中进行错误捕获
  getCont().then().catch((e) => console.log(e))
  如果async函数中使用了try catch 那么后面的then方法将会进入成功态 【相当于promise返回的是 undefined 】


上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号