saber酱的抱枕

努力变强

09/25
08:22
学习

JavaScript 使用 async/await 解决异步回调问题

JavaScript 使用 async/await  解决异步回调问题

异步代码经常和回调函数(callback function)挂钩。在以前,回调函数的写法是嵌套形式的,层数多了就形成了“回调地狱”,层层缩进看的人欲仙欲死,理解起来也不直观。

如本文开头的截图,是依次加载 5 个 js 文件,一个加载完了再加载下一个。

如果用传统写法,伪代码大概如下:

ajax 加载 1() {
	完成 {
		ajax 加载 2() {
			完成 {
				ajax 加载 3() {
					完成 {
						ajax 加载 4() {
							完成 {
								ajax 加载 5() {
									完成 {
										console.log('加载完成');
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

回调地狱完成了。


ES 2015 提出了 Promise 对象,用 then 处理 Promise 对象,形式是链式调用,回调函数不必被层层嵌套,也就不再产生回调地狱了。

如下代码:(依次加载 5 个 js 文件,并生成 blob url)

var js_urls = ['https://cdn.jsdelivr.net/npm/@trigrou/zip-js@1.0.0/WebContent/zip.js', 'https://cdn.jsdelivr.net/npm/@trigrou/zip-js@1.0.0/WebContent/z-worker.js', 'https://cdn.jsdelivr.net/npm/@trigrou/zip-js@1.0.0/WebContent/inflate.js', 'https://cdn.jsdelivr.net/npm/gif.js@0.2.0/dist/gif.js', 'https://cdn.jsdelivr.net/npm/gif.js@0.2.0/dist/gif.worker.js'];

function loadJS() {
	let url = js_urls.shift();
	fetch(url)
		.then(res => res.blob())
		.then(data => {
			let blob_url = URL.createObjectURL(data);
			console.log(blob_url);
			if (js_urls.length === 0) {
				console.log('加载完毕');
			} else {
				loadJS();
			}
		});
}

loadJS();

这样已经好多了。


ES 2016 提出了 async/await。上面用 then 的时候,其实 then 里面是回调函数,而 await 可以把结果取出来,形式和 then 不一样,看起来也不错。

var js_urls = ['https://cdn.jsdelivr.net/npm/@trigrou/zip-js@1.0.0/WebContent/zip.js', 'https://cdn.jsdelivr.net/npm/@trigrou/zip-js@1.0.0/WebContent/z-worker.js', 'https://cdn.jsdelivr.net/npm/@trigrou/zip-js@1.0.0/WebContent/inflate.js', 'https://cdn.jsdelivr.net/npm/gif.js@0.2.0/dist/gif.js', 'https://cdn.jsdelivr.net/npm/gif.js@0.2.0/dist/gif.worker.js'];

async function loadJS() {
	let url = js_urls.shift();
	let js_file = await fetch(url);
	let js_blob = await js_file.blob();
	let blob_url = URL.createObjectURL(js_blob);
	console.log(blob_url);
	if (js_urls.length === 0) {
		console.log('加载完毕');
	} else {
		loadJS();
	}
}

loadJS();

虽然 await 和 then 处理的都是 promise 对象,但是 await 不需要像 then 一样,把 Promise 对象放到自己内部去处理。

这下是真的没有嵌套了。不过其实上面的 then 也可以满足需求了。我还是用 then 习惯些, async/await 的使用经验太少了。

相关资料:

JavaScript:async/await的基础用法
阮一峰 ECMAScript 6 入门

JavaScript 使用 async/await 解决异步回调问题