JS异步编程的几种方式及区别
- js 是单线程语言
- 所谓异步,就是指在执行一件任务,这件任务分A、B两个阶段,执行完A阶段后,需要去做另外一个任务得到结果后才能执行B阶段。
- 异步编程有以下几种常用方式:callback、Promise、Generator、async。
1.callback
指通过函数传参传递到其他执行代码的,某一块可执行代码的引用,被主函数调用后又回到主函数
缺点:如果存在多个任务,需要层层嵌套,形成回调地狱,代码会显得冗余且耦合度很高。降低代码的阅读性和可维护性
2.promise
常用于解决异步回调问题,可以将回调函数的嵌套改为链式调用。
优点:解决回调地狱
缺点:还是有些多余的代码,如被Promise包装的函数有一堆的new Promise、then、catch
3.generator函数
是ES6提供的一种异步解决方案,由每执行一次函数返回的是一个遍历器对象,返回的对象可以依次遍历Generator里面的每一个状态
需要用遍历器对象的next方法来执行函数
Generator有三个特征:
- 函数命名时function后面需要加*
- 函数内部有yield;外部执行需要调用next方法。
- 每个yield会将跟在她后面的值包裹成一个对象的返回,
返回的对象中包括返回值和函数运行状态,直到return,
返回done为true。
优点:相比Promise在写法上更加精简且逻辑清晰
4.async
是Generator函数的语法糖
相比Generator函数,async函数在写法上的区别就是async替代了*,await替代了yield,并且async自带执行器
async函数返回的Promise,必须等到函数体内所有await后面的Promise对象都执行完毕后,或者return或者抛错之后才能改变状态;也就是只有async里面的异步操作全部操作完,才能回到主任务来,并且在then方法里面继续执行主任务。
async与Promise、Generator函数之间的对比
- Promise虽然很好的解决了地狱回调的问题,但是代码中有很多与语义无关的then、
- Generator函数需要自动执行器来执行函数,且yield后面只能是Promise对象或者Thunk函数。
- async 函数的实现最简洁,最符合语义,几乎没有语义不相关的代码。与Generator相比不需要程序员再提供一个执行器,async本身自动执行,使用起来方便简洁。
// callback异步
function callback() {
let readFile;
readFile(fileA, function (data) {
readFile(fileB, function (data) {
// ......
});
});
}
// promise
function getData() {
let require = new Promise((res, rej) => {
res(), rej();
});
require
.then((res) => {
let result = res.data;
})
.catch((err) => {
let error = err.message;
});
}
// generator
function * foo(){
yield getFirstData;
yield getSecondData;
return getThirdData
}
let require = foo()
require.next()
require.next()
// async
let getListData = async function(){
let result = await reqGetListData()
if(result.code = 200){
// ...
}
}