JavaScript是单线程的,引入异步编程可以让JavaScript实现’多线程’。
ES6以前的异步编程方法:
回调函数
事件监听
发布/订阅
Promise对象
ES7的Async函数提出了异步编程的终极解决方案
异步的概念:
把一个任务分成两段,先执行第一段,再去做其他的事,等准备工作做完,再回头执行第二段。不连续的执行
1)回调函数
nodejs规定回调函数的参数一必须是err
var fs=require('fs');
fs.readFile('/user/info', function (err, data) {
if (err) throw err;//无法捕捉,所以把错误当作参数传入第二段
console.log(data);
});
缺点:多个回调函数嵌套
2)Promise对象:链式调用
var readFile = require('fs-readfile-promise');
readFile(fileA)
.then(function(data){
console.log(data.toString());
})
.then(function(){
return readFile(fileB);
})
.then(function(data){
console.log(data.toString());
})
.catch(function(err) {
console.log(err);
});
优点:异步任务的两段执行可以看的更清楚
缺点:代码冗余
协程
运行流程
- 协程A开始执行
- A暂停,执行权限执行到B
- 过一段事件后,B交还执行权限
- A恢复执行
Generator是ES6对协程的实现
function *asyncJob() {
//读取文件案例
// ...其他代码
//首次调用next运行到这里,开始执行readFile函数,这个函数暂停执行
//在readFile中,完成读取后再调用这个Generator的next并将返回的结果传入
//这个结果就会作为yield的语句的返回值赋给f,然后继续执行到下一个yield
var f = yield readFile(fileA);
// ...其他代码
}
异步任务的封装:
var fetch = require('node-fetch');
function* gen(){
var url = 'https://api.github.com/users/github';
var result = yield fetch(url);
console.log(result.bio);
}
var g = gen();
var result = g.next();
result.value.then(function(data){
return data.json();
}).then(function(data){
g.next(data);
});