ES6-异步函数
Generator
是一个状态机,它封装了多个内部状态。执行它将生成一个遍历器对象。
Generator有2个特征:
声明时使用function*
函数内部使用
yield
声明内部状态调用函数后,函数并不执行,而且返回的也不是函数运行结果,而是一个指向内部状态的对象。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
yield
相当于暂停执行标识,next()
相当于恢复执行标识,每调用一次next()
,Generator
函数才执行一次,直到遇到下一个yield
或者return
,当遇到yield
或ruturn
时,会在此暂停,并将其代表的值作为value返回。done
是遍历标识符,表示是否完成遍历。
yield表达式
yield
表达式只能用在Generator
函数中yield
表达式如果用在另一个表达式之中,必须放在园括号中yield
表达式用作函数参数或放在赋值表达式的右边可以不加括号- yield* 表达式用来在一个Generator函数执行另一个Generator函数
function* foo(a,b){
yield a;
yield b;
return a+b;
}
function* demo() {
console.log('Hello' + yield); // SyntaxError
console.log('Hello' + yield 123); // SyntaxError
console.log('Hello' + (yield)); // OK
console.log('Hello' + (yield 123)); // OK
foo(yield 'a',yield 'b')//OK
let input = yield;
}
next方法
yield
表达式本身没有返回值,next
方法可以带一个参数,该参数就被当作了yield表达式的对应变量。
function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var a = foo(5);
a.next() // Object{value:6, done:false},第一次会将传入的参数赋值给x
a.next() // Object{value:NaN, done:false},由于yield并没有返回值,所以y为undefined
a.next() // Object{value:NaN, done:true}
var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }
Generator
返回的并不是一个对象,而是一个指针对象,调用next
方法会将指针指向下一个阶段。每一个yield
都表示一个阶段,跟下一个阶段并不影响。
Generator.prototype.return()
Generator
函数返回的遍历器对象,还有一个return
方法,可以返回给定的值,并且终结遍历Generator
函数。
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next() // { value: 1, done: false }
g.return('foo') // { value: "foo", done: true }
g.next() // { value: undefined, done: true }
Generator
并不能自动执行,所以它需要一个自动执行器,常用的就是co函数库
async
async
函数是Generator
函数的语法糖
区别如下:
- 将
*
替换为了async
且async
提到了function
的前面,表示函数中有异步操作 - 将
yield
替换为了await
,表示紧跟后面的表达式需要等待结果 async
函数自带了执行器,不需要像Generator
一样需要next
方法才能执行yield
命令后面只能是 Thunk 函数或 Promise 对象,而async
函数的await
命令后面,可以是Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)async
返回的是一个Promise
对象,Generator
函数返回的是一个遍历器对象
var fs = require('fs');
var readFile = function (fileName) {
return new Promise(function (resolve, reject) {
fs.readFile(fileName, function(error, data) {
if (error) reject(error);
resolve(data);
});
});
};
var gen = function* () {
var f1 = yield readFile('/etc/fstab');
var f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
//async写法
var asyncReadFile = async function () {
var f1 = await readFile('/etc/fstab');
var f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
async
返回一个promise
对象,所以return
返回的值将作为then方法的参数。
async
函数必须等内部所有的await命令后面的Promise对象执行完成才会执行then
方法指定的回调函数。
await
await
返回一个Promise
对象,如果不是,会被转换成一个立即执行的Promise
对象,await
将等待当前行执行完成才会继续之后的内容
async function f() {
await Promise.reject('出错了')
.catch(e => console.log(e));
return await Promise.resolve('hello world');
}
f().then(v => console.log(v))
// 出错了
// hello world