异步编程(1) Generator
2017-03-09 本文已影响0人
LElysion
异步的概念
一般同步的程序是请求文件-等待文件-处理文件,而异步则是在等待文件的阶段可以处理其他任务,这便是异步
回调函数
Js通过回调函数实现异步编程,回调函数就是将处理文件这一阶段单独卸载一个函数里,等再次执行这个任务时便直接调用该函数
fs.readFile('/etc/passwd', function(err, data){
/*
这里便是回调函数
只有当读取到/etc/passwd时才会执行
*/
if(err) throws err
console.log(data)
})
Promise
不过如果依次读取多个文件时会出现多重嵌套,这便是callback hell
/*callback hell*/
fs.readFile(fileA, function (err, data) {
fs.readFile(fileB, function (err, data) {
// ...
});
});
Promise就是为了解决这个问题才出现的,它提供一个新的写法
var readFile = require('fs-readfile-promise');
/*返回一个Promise版本的readFile函数*/
readFile(fileA)
.then(function(data){ /*Promise提供then方法加载回调函数*/
console.log(data.toString());
})
.then(function(){
return readFile(fileB);
})
.then(function(data){
console.log(data.toString());
})
.catch(function(err) {/*catch方法捕捉抛出错误*/
console.log(err);
});
协程(coroutine)
通过管理函数执行权来获得异步编程能力
通过yield
命令,可以让同步中的请求文件跟处理文件中断开来并且通过这开辟的新的时间来处理其他任务,这便是协程
function asnycJob() {
// ...其他代码
var f = yield readFile(fileA);/*执行到这里后执行权交给其他协程,暂停该进程*/
// ...其他代码
}
Generator函数
协程在ES6中的实现,最大特点是可以交出函数的执行权
function* gen(x) { /*在函数名之前加星号以示区别*/
var y = yield x+2
return y
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }
调用Generator函数执行该函数是不会返回结果而是返回指针对象
通过调用指针的.next()
方法会指向第一个遇到的yield语句,也就是分阶段执行Generator函数
每次调用next方法都会返回当前阶段信息
- value: yield语句后面表达式的值,表示当前阶段的值
- done: 表示Generator函数是否执行完毕
简单来说Generator函数就是一个封装的异步任务的容器,在异步操作需要暂停的地方都用yield语句注明,再通过.next()
方法来分阶段输出
Generator函数的数据交换和错误处理
.next()
方法返回value属性便是对外输出的数据,同样next方法也可以接受参数,赋值给value
function* gen(x){
var y = yield x + 2;
return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: true }
使用指针对象g的throw方法抛出的错误可以被函数体被的try..catch
代码捕获
g.throw('warming!!!')
Generator用法
var fetch = require('node-fetch');
function* gen(){
var url = 'https://api.github.com/users/github';
var result = yield fetch(url); /*当需要的时候在fetch该api*/
console.log(result.bio);}/*.bio: 数据*/
使用该方法
var g = gen();
var result = g.next();
result.value.then(function(data){
return data.json();
}).then(function(data){
g.next(data);
});