Skip to content
文章目录

promise顺序执行的多种方案

回调形式

js
const f1 = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('p1 runing')
      resolve(1)
    }, 1000)
  })

const f2 = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('p2 runing')
      resolve(2)
    }, 1000)
  })

// 使用回调形式
f1().then(() => {
  f2()
})

async、await 的方案

js
// 使用async await
async function asyncPromise() {
  await f1()
  f2()
}

reduce 方案

js
const arr = [f1, f2]
const runPromiseInsequence = (array, value) =>
  array.reduce((promiseChain, currentFunction) => promiseChain.then(currentFunction), Promise.resolve(value))
runPromiseInsequence(arr, 'init')

递归方案

js
// 使用递归
const arr = [f1, f2]
function sequencePromise(arr) {
  const pro = arr.shift()
  if (pro) {
    pro().then(() => {
      sequencePromise(arr)
    })
  }
}
sequencePromise(arr)

任务队列

普通任务队列

js
class Queue {
  constructor() {
    let waitingQueue = []
    let isRunning = false //记录是否有未完成的任务
    function execute(task, resolve, reject) {
      task()
        .then(data => {
          resolve(data)
        })
        .catch(e => {
          reject(e)
        })
        .finally(() => {
          //等待任务队列中如果有任务,则触发它;否则设置isRunning = false,表示无任务状态
          if (waitingQueue.length) {
            const next = waitingQueue.shift()
            execute(next.task, next.resolve, next.reject)
          } else {
            isRunning = false
          }
        })
    }
    return function (task) {
      return new Promise((resolve, reject) => {
        if (isRunning) {
          waitingQueue.push({ task, resolve, reject })
        } else {
          isRunning = true
          execute(task, resolve, reject)
        }
      })
    }
  }
}

const queue = new Queue()
const task1 = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('task1')
    }, 3000)
  })
const task2 = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('task2')
    }, 1000)
  })
const queue = new Queue()
queue(task1).then(data => console.log(data))
queue(task2).then(data => console.log(data))
//result
//task1
//task2

有时间间隔的任务队列

实现一个有时间间隔,并且超时后会中断任务的任务队列

有几个要点:超时后终止当前任务直接开始下一个任务;delay 时间后才会执行下一个任务;如果任务 delay 了但没超时,则需要立即执行下一个任务

js
class Queue {
  constructor({ delay, timeout }) {
    let timer = null //当有任务执行时,设置超时检测的定时器
    let waitingQueue = [] //等待任务的队列
    function execute(task, resolve, reject) {
      let resolved = false //记录任务是否结束
      let executeNext = false //记录是否任务结束后,立即执行下一个任务
      let isTimeout = false // 是否超时
      task().then(data => {
        // 超时了,这个任务完成也不管了
        if (isTimeout) return // fix 原来没写着一行
        //任务未超时,则会进入这里
        resolve(data)
        resolved = true //标记任务完成
        clearTimeout(timer) //清除超时计时器
        timer = null
        if (executeNext) {
          //true代表任务是在delay后完成的,所以直接执行下一个任务
          const next = waitingQueue.shift()
          if (next) {
            execute(next.task, next.resolve, next.reject)
          }
        }
      })
      timer = setTimeout(() => {
        isTimeout = true
        reject('超时') //超时直接调用reject
        timer = null
        const next = waitingQueue.shift()
        if (next) {
          //立即执行下一个任务
          execute(next.task, next.resolve, next.reject)
        }
      }, timeout)
      //delay时间后,自动执行下一个任务
      setTimeout(() => {
        if (resolved) {
          //true代表上一个任务已经完成,可以直接执行下一个任务
          const next = waitingQueue.shift()
          if (next) {
            execute(next.task, next.resolve, next.reject)
          }
        }
        executeNext = true //标记当前任务完成后,立即执行下个任务(给任务在delay之后完成用)
      }, delay)
    }
    return function (task) {
      return new Promise((resolve, reject) => {
        if (!timer) {
          //没有任务,则直接执行
          execute(task, resolve, reject)
        } else {
          //否则 将任务放入等待队列中
          waitingQueue.push({ task, resolve, reject })
        }
      })
    }
  }
}
const task1 = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('task1')
    }, 3000)
  })
const task2 = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('task2')
    }, 2000)
  })
const task3 = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('task3')
    }, 1000)
  })
const queue = new Queue({ delay: 2000, timeout: 3000 })
queue(task1).then(data => console.log(data))
queue(task2).then(data => console.log(data))
queue(task3).then(data => console.log(data))
//task1
//task2
//task3
const task4 = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('task4')
    }, 4000)
  })
queue(task4).then(data => console.log(data))
queue(task1).then(data => console.log(data))
queue(task2).then(data => console.log(data))
queue(task3).then(data => console.log(data))
//Uncaught (in promise) 超时
//task1
//task2
//task3

参考资料

js 实现任务(promise 任务)队列

Promise 队列的实现