JavaScript异步处理的那些事儿
栏目: JavaScript · 发布时间: 5年前
内容简介:之前总结了关于 JavaScript 异步的下面是关于JS异步处理的各种方案:
之前总结了关于 JavaScript 异步的 事件循环与消息队列 机制以及 ES6 带来的 微任务与宏任务 的知识。传送门
下面是关于JS异步处理的各种方案:
callback >> ES6 Primise >> async/await 复制代码
没有异步处理
先看一段代码:
// 假设有一个耗时的异步请求 ajax,在 2 秒后打印日志 function ajax () { // do something... setTimeout(() => { console.log('Hello, Zavier Tang!') }, 2000) } ajax() // do something... console.log('The end.') // The end. // Hello, Zavier Tang! 复制代码
这里模拟了一个简单的异步网络请求,并在 2 秒后打印 "Hello, Zavier Tang!",然后做一些处理("do something")后,打印结束 "The end."。
结果是先打印的 "The end."。
显然这并不是我们要的结果,"异步请求" ajax
中的 setTimeout
并没有阻塞代码的执行,而是直接执行了 console.log()
。
异步的解决方案
1. 传统(可怕)的 callback 回调地狱
同样是上面的异步网络请求,这里使用 callback 回调函数的方式解决 JavaScript 同步带来的问题。
function ajax (fn) { // do something... setTimeout(() => { console.log('Hello, Zavier Tang!') fn() }, 2000) } ajax(() => { // do something... console.log('The end.') }) // Hello, Zavier Tang! // The end. 复制代码
这里我们直接把异步请求之后要做的一些操作做为回调函数,传递到 ajax 中去,并在异步请求结束后执行回调函数里的操作。
问题似乎已经解决了??但是,如果有多个异步请求,并且在每个异步请求完成后都执行一些操作,那代码就会像下面这样:
function ajax (fn) { // do something... setTimeout(() => { console.log('Hello, Zavier Tang!') fn() }, 500) } ajax(() => { // do something... console.log('The end 1.') ajax(() => { // do something... console.log('The end 2.') ajax(() => { // do something... console.log('The end 3.') ajax(() => { // do something... console.log('The end 4.') ajax(() => { // do something... console.log('The end 5.') // ...... // ...... }) }) }) }) }) // Hello, Zavier Tang! // The end 1. // Hello, Zavier Tang! // The end 2. // Hello, Zavier Tang! // The end 3. // Hello, Zavier Tang! // The end 4. // Hello, Zavier Tang! // The end 5. 复制代码
看起来很吓人!!
如果是这样:请求1结束后进行请求2,然后还有请求3、请求4、请求5,并且请求2还可能依赖于请求1的数据,请求3依赖于请求2的数据,不停的一层一层嵌套,对于错误的处理也极不方便,所以称之为 callback 回调地狱。
2. 下一代异步解决方案:Promise
ES6 的 Promise 被称为 JS 异步的下一代解决方案。
关于 Promise:
- 用于异步计算。
- 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果。
- 可以在对象之间传递和操作 Promise,方便处理队列。
接下来使用 Promise 处理异步:
function ajax (word) { return new Promise((resolve) => { // do something... setTimeout(() => { resolve('Hello ' + word) }, 500) }) } ajax('请求1') .then((word) => { console.log(word) console.log('The end 1.') return ajax('请求2') }) .then((word) => { console.log(word) console.log('The end 2.') return ajax('请求3') }) .then((word) => { console.log(word) console.log('The end 3.') }) // .catch(() => {}) // Hello 请求1 // The end 1. // Hello 请求2 // The end 2. // Hello 请求3 // The end 3. 复制代码
上面还是连续的异步请求,每次请求后打印日志。这样看起来比上面的回调地狱舒服多了,每个请求通过链式的调用,在最后可以对所有的请求进行错误处理。
但,似乎还并不是特别优雅。
3. 终极解决方案:async/await
关于 async/await 的简介:
- async/await 是写异步代码的新方式,不同于以前的 callback 回调函数和 Promise。
- async/await 是基于 Promise 实现的,不能用于普通的回调函数。
- async/await 与 Promise 一样,是非阻塞的。
- async/await 使得异步代码看起来像同步代码。
体验一下神奇的 async/await:
// 接上面的代码 async function doAsync () { const word1 = await ajax('请求1') console.log(word1) console.log('The end 1') const word2 = await ajax('请求2') console.log(word2) console.log('The end 2') const word3 = await ajax('请求3') console.log(word3) console.log('The end 3') } doAsync() // Hello 请求1 // The end 1 // Hello 请求2 // The end 2 // Hello 请求3 // The end 3 复制代码
这样看起来,更优雅了。没有任何括号,也没有 callback,没有 then,直接申明 async,使用 await 等待异步执行完成,看起来也更像是同步的代码。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。