学无止境,望君把握时间
.Generator 函数
在了解async函数前,我们需要知道一下Generator 函数。
作用:
接触过Ajax请求的会遇到过异步调用的问题,为了保证调用顺序的正确性,一般我们会在回调函数
中调用,也有用到一些新的解决方案如Promise相关的技术。
在异步编程中,还有一种常用的解决方案,它就是Generator生成器函数。顾名思义,它是一个
生成器,它也是一个状态机,内部拥有值及相关的状态,生成器返回一个迭代器Iterator对象,
我们可以通过这个迭代器,手动地遍历相关的值、状态,保证正确的执行顺序。
使用:
1.声明:
Generator的声明方式类似一般的函数声明,只是多了个*号,并且一般可以在函数内看到yield关键字
function* showWords() {
yield 'one';
yield 'two';
return 'three';
}
var show = showWords();
show.next() // {done: false, value: "one"}
show.next() // {done: false, value: "two"}
show.next() // {done: true, value: "three"}
show.next() // {done: true, value: undefined}
如上代码,定义了一个showWords的生成器函数,调用之后返回了一个迭代器对象(即show)
调用next方法后,函数内执行第一条yield语句,输出当前的状态done(迭代器是否遍历完成)以及相应值(一般为yield关键字后面的运算结果)
每调用一次next,则执行一次yield语句,并在该处暂停,return完成之后,就退出了生成器函数,后续如果还有yield操作就不再执行了
2.注意:yield 与yield*的区别:
废话少说,小二 上代码:
function* showWords() {
yield 'one';
yield showNumbers();
return 'three';
}
function* showNumbers() {
yield 10 + 1;
yield 12;
}
var show = showWords();
show.next() // {done: false, value: "one"}
show.next() // {done: false, value: showNumbers}
show.next() // {done: true, value: "three"}
show.next() // {done: true, value: undefined}
增添了一个生成器函数,我们想在showWords中调用一次,简单的 yield showNumbers()之后发现并没有执行函数里面的yield 10+1
因为yield只能原封不动地返回右边运算后值,但现在的showNumbers()不是一般的函数调用,返回的是迭代器对象
所以换个yield* 让它自动遍历进该对象
小二 继续:
function* showWords() {
yield 'one';
yield* showNumbers();
return 'three';
}
function* showNumbers() {
yield 10 + 1;
yield 12;
}
var show = showWords();
show.next() // {done: false, value: "one"}
show.next() // {done: false, value: 11}
show.next() // {done: false, value: 12}
show.next() // {done: true, value: "three"}
值得注意的是yield 与yield*只能在Generator 函数使用。
function showWords() {
yield* 'one';
}
var show = showWords();
show.next() // Uncaught ReferenceError: yield is not defined
虽然换成yield*不会直接报错,但使用的时候还是会有问题,因为’one’字符串中没有Iterator接口,没有yield提供遍历
3.next()调用中的传参
参数值有注入的功能,可改变上一个yield的返回值,如以下代码:
function* showNumbers() {
var one = yield 1;
var two = yield 2 * one;
yield 3 * two;
}
var show = showNumbers();
show.next().value // 1
show.next().value // NaN
show.next(2).value // 6
解析:
第一次调用next之后返回值one为1,但在第二次调用next的时候one其实是undefined的,
因为generator不会自动保存相应变量值,我们需要手动的指定,这时two值为NaN,
在第三次调用next的时候执行到yield 3 * two,通过传参将上次yield返回值two设为2,
得到结果。(值得注意的是generator不会保存相应变量值!!!)。
Generator函数先了解到这,现在开始正题:
1.首先:async是什么:
一句话,它就是 Generator 函数的语法糖,async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。
在Generator函数中的代码如此:
const fs = require('fs');
const readFile = function (fileName) {
return new Promise(function (resolve, reject) {
fs.readFile(fileName, function(error, data) {
if (error) return reject(error);
resolve(data);
});
});
};
const gen = function* () {
const f1 = yield readFile('/etc/fstab');
const f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
转成async代码就应是如此:
const asyncReadFile = async function () {
const f1 = await readFile('/etc/fstab');
const f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
一比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,
将yield替换成await,仅此而已。
async只不过将Generator进行了一些改进;
2.async具体使用和优点:
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句
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);
//50ms后打印出 hellow world
关键字解释:
1.async 表示这是一个 async 函数,而 await 只能在这个函数里面使用。
2.await 表示在这里等待 await 后面的操作执行完毕,再执行下一句代码。
3.await 后面紧跟着的最好是一个耗时的操作或者是一个异步操作(当然非耗时的操作也可以的,
但是就失去意义了)。
3.错误处理:
如果await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject。
同样多说无益 上代码:
async function f() {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出错了
防止出错,可以将其添加在try catch中。代码如下:
async function main() {
try {
const val1 = await firstStep();
const val2 = await secondStep(val1);
const val3 = await thirdStep(val1, val2);
console.log('Final: ', val3);
}
catch (err) {
console.error(err);
}
}
总结:
说白了,就一个道理:async也是Promise对象,我们可以在async后面添加then或者catch来防止出错。