前言
最近在看阮老师的JavaScript基础和es6文档,其中关于异步的处理,我觉得有必要整理一下。这有助于我逐步改善自己的编程风格,提升代码质量。
Promise
文档传送门:Promise 对象
promise已经是现如今最广泛使用的异步解决方案,几乎已经没有人去使用回调来解决异步问题。callback最广为人知的问题是回调地狱,因此promise应运而生。然鹅,promise的链式调用也没有从根本上解决这个问题,.then()的调用只是换了一种写法;同时,promise的错误处理也是一个大麻烦。
Promise.all()
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
1 | const p = Promise.all([p1, p2, p3]); |
上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
先来看个例子:
1 | function sleep(t){ |
这个方法可以应用在多个http需要同时请求时的情况。需要注意的是,这时的错误处理需要分情况处理:如果原Promise实例有自己的catch处理,则不会触发all的catch,反之会触发all的catch
Promise.race()
这个方法与all类似,区别是只要有一个Promise先改变了状态(resolve,reject皆可),就会传回回调。这个方法暂时没有想到什么应用方向(感觉它与高并发的秒杀业务流程类似)
Promise.any()
Promise.any()跟Promise.race()方法很像,只有一点不同,就是不会因为某个 Promise 变成rejected状态而结束。
这是es2021引入的新方法。谨慎使用
async/await
文档传送门:async 函数
async 函数是什么?一句话,它就是 Generator 函数的语法糖。
文档中提到了 Generator 函数,这个函数我粗略的看了一下,它的异步应用似乎只是它延申出的应用而已,本身是实现了函数的分步执行。在有了async/await之后,似乎并不需要它来实现异步了。参考:ES6+中的Generator 函数有何特别之处?
基本使用
作为一个语法糖,可以将上述代码简化:
1 | async function f(){ |
sleep()函数也可以用async/await写法,除了写法不同,实际运行效果一样:
1 | async function sleep(t){ |
错误处理
如果使用多个await处理异步函数,在前一个函数返回reject时,之后不会执行。为了防止出错,需要将其放在try…catch代码块之中。
一个文档中的使用例子,可以实现多次重复尝试。
1 | const superagent = require('superagent'); |
持续学习
关于js的异步编程,我自认还没有完全了解,只是了解了写法和部分原理,只有持续学习,看看在实际应用中还是否会遇上问题。
几篇不错的文章(可能会更新):