JavaScript异步编程
为什么使用异步编程
因为JavaScript函数是单线程执行,所以异步编程十分重要,如果没有异步编程,那么程序一定会很卡很慢。
概念
异步,就是说一个任务不是连续完成的,可以理解成该任务被分成两段,先执行第一段,然后转而执行其他任务。等准备好后再回过头执行第二段函数。
实现异步
最原生
Js底层通常采用回调函数来实现异步(callback),这种写法一般情况没任何问题,但涉及到多层嵌套回调的话。会使代码由纵向变成横向发展,继而混乱不清无法管理,会很麻烦。
Promise实现
Promise就是为了解决多层回调带来的高耦合,回调地狱问题。他最早由社区提出,在es6被写进语言标准。他不是新的语法功能,
只是一种新的写法,将回调函数的嵌套该问链式调用,进而代码更清晰。
Promise本身是一个容器,里边存着未来才会结束的时间结果。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
其内部接受一个函数作为参数,函数的两个参数分别是resolved和rejected,其中resolved作用是将pending改为成功,并将参数传递出去。rejected的作用是将pending改为失败,同时将错误信息作为参数传递出去。
接收处理结果的方式有两种,第一种是在then里边写两个函数,分别接受成功和失败状态。第二种是then接收成功状态,catch接收失败状态。常用第二种。
Generator实现
Generator函数是协程在es6上的实现,最大的特点就是可以交出执行权(暂停执行)。一整个Generator函数就是一个封装的异步任务,或者说执行异步的容器。异步操作需要暂停的地方使用yield语句著名。优化了promise在处理在处理复杂任务是语义不清楚问题。
但是Generator无法自动执行,需要借助Thunk或者co模块执行器。目前该函数使用的较少。
async函数实现
ES2017标准引入了async函数,使得异步操作变得更加方便,本质就是Generator的语法糖。
和Generator相比较的优势:
1,它内置执行器,无需依赖co模块
2,更清晰的语义,async和await代替了*和yield
3,更广的适用性,后边可以是promise对象和原始值(会立即转换成resolved的promise对象)
4,返回值是Promise,可以使用then指定下一步操作
async函数可以看做是多个异步操作包装成一个Promise对象,await命令就是then的语法糖。
基本用法:
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);