【JS】中断和恢复任务序列

前言

封装processTasks函数,实现以下需求

/**
 * 依次顺序执行一系列任务
 * 所有任务全部完成后可以得到每个任务的执行结果
 * 需要返回两个方法,start用于启动任务,pause用于暂停任务
 * 每个任务具有原子性,即不可中断,只能在两个任务之间中断
 * @param {...Function} tasks 任务列表,每个任务无参、异步
 */
function processTasks(...tasks){}

实现

初步框架如下

function processTasks(...tasks) {
  const result = []
  let i = 0 // 当前任务索引
  let isRunning = false // 是否正在运行
  
  return {
    async start() {
      isRunning = true
      while (i < tasks.length) {
        result.push(await tasks[i]())
        i++
        if (!isRunning) return // 暂停
      }
    },
    pause() {
      isRunning = false
    },
  }
}

继续改造start的返回,手动控制Promise:

function processTasks(...tasks) {
  const result = []
  let i = 0 // 当前任务索引
  let isRunning = false // 是否正在运行
  let prom = null // 记录promise结果,防止二次调用start时重复执行之前的任务

  return {
    start() {
      return new Promise(async (resolve, reject) => {
        if (prom) {
          // 结束了
          prom.then(resolve, reject)
          return
        }
        if (isRunning) return // 正在运行,防止多次调用
        isRunning = true
        while (i < tasks.length) {
          try {
            result.push(await tasks[i]())
          } catch (err) {
            isRunning = false
            reject(err)
            prom = Promise.reject(err)
            return // 失败终止
          }
          i++
          if (!isRunning && i < tasks.length - 1) return // 暂停
        }
        isRunning = true
        while (i < tasks.length) {
          try {
            result.push(await tasks[i]())
          } catch (err) {
            isRunning = false
            reject(err)
            prom = Promise.reject(err)
            return // 失败终止
          }
          i++
          if (!isRunning && i < tasks.length - 1) return // 暂停
        }
        // 成功
        isRunning = false
        resolve(result)
        prom = Promise.resolve(result)
      })
    },
    pause() {
      isRunning = false
    },
  }
}

测试

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="./aa.js"></script>
</head>

<body>
  <button id="start">开始任务</button>
  <button id="pause">暂停任务</button>
  <script>
    const tasks = []
    for (let i = 0; i < 5; i++) {
      tasks.push(() => new Promise(resovle => {
        setTimeout(() => {
          resovle(i)
        }, 2000);
      }))
    }
    const processor = processTasks(...tasks)
    start.onclick = async () => {
      console.log("开始任务");
      const results = await processor.start()
      console.log("任务执行完成:", results);
    }
    pause.onclick = () => {
      console.log("点击暂停");
      processor.pause()
    }
  </script>
</body>

</html>

使用场景

大文件分片上传

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

田本初

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值