异步队列实现记录

207 阅读1分钟
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Quequ</title>
</head>
<body>
	<script>
		/**
		 * 异步任务队列
		 * 可追加多个任务
		 * 自动执行
		 * 可获取前面任务结果
		 * 错误后自动重新执行
		 * 执行完队列后执行回调函数
		*/
		class Quequ {
			store = []
			results = []
			flag = false
			callback = function() {}
			push(fns, callback) {
				if(callback && callback instanceof Function) this.callback = callback
				if (Array.isArray(fns)) {
					fns.forEach(fn => {
						this.store.push(fn)
					})
				} else if (fns instanceof Function) {
					this.store.push(fns)
				} else {
					console.error('Arguments must be Array or Function')
					return
				}

				//追加后自动开始执行
				this.start()
			}
			async do(retryFn) {
				let fn = retryFn? retryFn: this.store.shift()
				try {
					let res = await fn()
					//存储执行结果,方便后续函数调用
					this.results.push({ name, value: res, error: null })
					if (this.store.length) {
						return this.do()
					}
				} catch(err) {
					let errMsg = err.message || err
					//错误后输出错误,并自动重试3次
					console.error(`${name} exec error, ` + errMsg)
					if (!fn._retrytime) fn._retrytime = 0
					if (fn._retrytime < 3) {
						fn._retrytime++
						return this.do(fn)
					} else {
						delete fn._retrytime
						this.results.push({ name, value: null, error: errMsg  })
					}
				}
			}
			async start(retryFn) {
				if(this.flag || !this.store.length) return
				this.flag = true
				await this.do()
				//执行完毕后执行回调,重置状态
				this.callback(this.results)
				this.flag = false
				this.results = []
				this.callback = function() {}
			}
			empty() { //返回队列状态
				return !this.store.length
			}
			results() { //获取执行结果
				return this.results
			}
		}
		let fn1 = () =>{
			return new Promise((r, j) => {
				setTimeout(() => {
					console.log('fn1')
					r('fn1')
				}, 1000)
			})
		}
		let fn2 = () => {
			return new Promise((r, j) => {
				setTimeout(() => {
					console.log('fn2')
					r('fn2')
				}, 1000)
			})
		}
		let fn3 = () => {
			return new Promise((r, j) => {
				setTimeout(() => {
					console.log('fn3')
					j('fn3')
				}, 1000)
			})
		}
		let quequ = new Quequ()
		quequ.push([fn1, fn2], (results) => {
			console.log(results)
		})
		// let quequ1 = new Quequ()
		quequ.push(fn3, (results) => {
			console.log(1111, results)
		})
		
	</script>
</body>
</html>