前言
封装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>
使用场景
大文件分片上传