async函数原理

学无止境,望君把握时间

.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来防止出错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值