构建Promise队列实现异步函数顺序执行

场景

  • 有a、b、c三个异步任务,要求必须先执行a,再执行b,最后执行c
  • 且下一次任务必须要拿到上一次任务执行的结果,才能做操作

思路

  • 我们需要实现一个队列,将这些异步函数添加进队列并且管理它们的执行,队列具有First In First Out的特性,也就是先添加进去的会被先执行,接着才会执行下一个(注意跟栈作区别)
  • 大家也可以类比一下jQuery的animate方法,添加多个动画也会按顺序执行

解决

  • 模拟3个异步函数

    // 异步函数a
    var a = function () {
      return new Promise(function (resolve, reject) {
        setTimeout(function () {
          resolve('a')
        }, 1000)
      })
    }
    
    // 异步函数b
    var b = function (data) {
      return new Promise(function (resolve, reject) {
        resolve(data + 'b')
      })
    }
    
    // 异步函数c
    var c = function (data) {
      return new Promise(function (resolve, reject) {
        setTimeout(function () {
          resolve(data + 'c')
        }, 500)
      })
    }
    
  • 解决方法一(使用then链式操作)

    • 特点:可以满足需求,但是书写比较繁琐

    • 代码

      //链式调用
      a()
        .then(function (data) {
          return b(data)
        })
        .then(function (data) {
          return c(data)
        })
        .then(function (data) {
          console.log(data)// abc
        })
      
  • 方法二(forEach构建队列)

    • 特点:封装方法,可移植到别处使用

    • 代码

      // 构建队列
      function queue(arr) {
        var sequence = Promise.resolve()
        arr.forEach(function (item) {
          sequence = sequence.then(item)
        })
        return sequence
      }
      
      // 执行队列
      queue([a, b, c])
        .then(data => {
          console.log(data)// abc
        })
      
  • 方法三(reduce构建队列)

    • 同方法二,只是显得更装x点

    • 代码

      function queue(arr) {
        return arr.reduce((a, b) => {
          a = a.then(b)
          return a
        }, Promise.resolve())
      }
      queue([a, b, c])
        .then(data => {
          console.log(data)// abc
        })
      
  • 方法四(使用async、await构建队列)

    • 利用最新的语法糖特性

    • 代码

      async function queue(arr) {
        let res = null
        for (let promise of arr) {
          res = await promise(res)
        }
        return await res
      }
      queue([a, b, c])
        .then(data => {
          console.log(data)// abc
        })
      
  • 顺便说一句,bluebird的Promise.reduce也可以用来顺序执行函数,但是可使用的场景非常有限,一般用来读取文件信息,而以上给出的方法,不管你在异步函数中做了什么,只要函数最后返回了一个Promise对象,都可以使用

实战

工作中的异步请求肯定不会像上面的a、b、c这么直白和傻瓜的,都需要我们去抽象封装的

// 模拟复杂封装过的请求
function mockRequest(time) {// time-模拟几秒的请求
  return function (data) {// data-上一个请求传来的值
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log(time, data, 111);
        resolve(data ? data + time : time)// 第一个请求没有接收值,后面的才接收值
      }, time * 1000)
    })
  }
}

function queue(arr) {
  return arr.reduce((a, b) => {
    a = a.then(b)
    return a
  }, Promise.resolve())
}

// 执行队列
queue([mockRequest('2'), mockRequest('1'), mockRequest('3')])
  .then(data => {
    console.log(data, 222)// 213
  })
  • 12
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值