美文网首页
async函数

async函数

作者: c菜鸟 | 来源:发表于2018-03-11 19:19 被阅读0次

    首先看一下下列代码

    var gen = function* (){
     var a = yield readFile();
     console.log(a);
     var b= yield readFile();
     console.log(b);
    }

    接下来用async形式来表示generator函数

    var gen = async function(){
     var a = await readFIle();
     console.log(b);
     var b = await readFile();
     console.log(b);
    }

    从以上可以看出async函数就是在generator函数上改进的,就是把*改为async,然后把yield改为await,但是他在generator函数上有一些改进

    哪些改进呢?


    • 内置执行器
      在我的另一篇博客中说出generator函数执行,需要为他写自动执行器,例如基于thunk函数的自动执行器,还有基于promise的自动执行器,还有就是co模块,但是async函数只要调用它就自己执行
    • 更好的语义
    • 更广泛的使用
      co模块的yield语句后面必须是thunk函数或者是promise对象,但是await函数后面可以是原始类型的值
    • 返回的是promise对象
      可以使用then等

    使用方法


    async function getStockByName(name){
     const symbol = await getStockSymbol(name);
     const stockPrice = await getStockPrice(symbol);
     return stockPrice;
    }
    getStockByName('sportShoe').then(function(result){
     console.log(result);
    })

    我们可以看出只要我们调用一次getStockByName(),就自动执行,所以最后的result就是stockPrice

    语法


    返回Promise对象

    调用async函数会返回一个promise对象,所以才可以调用then方法,then方法中的函数的参数就是async函数返回的值

    const aw = async function(age){
     var name = await search(age);
     return name;
    }
    aw(20).then(name => console.log(name));

    promise对象的状态变化

    只有内部的所有异步过程结束后,才会调用then方法,或者抛出错误,或者遇到return语句

    错误处理

    我建议大家把所有的await语句都放在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);
    }
    }

    注意的内容

    let foo = await getFoo();
    let bar = await getBar();

    以上函数是独立的过程,被写成继发关系,就是顺序进行,这样会导致很费时,怎样会写成同时进行
    有一下俩种写法

    // 写法一
    let [foo, bar] = await Promise.all([getFoo(), getBar()]);
    // 写法二
    let fooPromise = getFoo();
    let barPromise = getBar();
    let foo = await fooPromise;
    let bar = await barPromise;

    promise.all()方法就是将多个promise实例包装成一个
    await命令必须写在async函数中写在别的函数中会出错

    async函数的实现的原理

    其实就是把generator函数写到一个具有自动执行代码的函数,然后在返回这个函数,和基于thunk函数的自动执行器基本一致,就不仔细分析async函数的源码了

    顺序执行完一系列操作

    promise的写法

    function loginOrder(urls){
    Const textPromises = urls.map(url => {
    Return fetch(url).then(response => response.text());
    })
    TextPromise.reduce((chain, textPromise) => {
    Return chain.then(() => textPromise)
    .then(text => console.log(text));
    }, Promise.resolve());
    }

    接下来看一下用async函数来表示上述操作

    async function logInOrder(urls) {
    for (const url of urls) {
    const response = await fetch(url);
    console.log(await response.text());
    }
    }

    可以看出来用async表示非常简洁,但是这样会有一个问题所有提取网页都是继发,这样会很浪费时间,继发·就是提取网页是按照顺序进行的,所以我们现在要把它改成同时提取网页,代码如下

    async function logInOrder(urls) {
    // 并发读取远程URL
    const textPromises = urls.map(async url => {
    const response = await fetch(url);
    return response.text();
    });
    // 按次序输出
    for (const textPromise of textPromises) {
    console.log(await textPromise);
    }
    }

    因为在上述map函数中,匿名函数是async函数,所以await如果是在async函数中,那么这些await后面的操作都是同步进行的 ,这样就不会耗时了

    异步遍历

    我们都知道同步遍历器是部署在对象的Symbol.iterator的属性上的,但是异步遍历器是部署在对象的Symbol.asyncIterator属性上的
    以下代码是一个异步遍历器的例子

    const asyncIterable = createAsyncIterable(['a', 'b']);
    const asyncIterator = asyncIterable.Symbol.asyncIterator();
    asyncIterator
    .next()
    .then(iterResult1 => {
      console.log(iterResult1); // { value: 'a', done: false }
      return asyncIterator.next();
    })
    .then(iterResult2 => {
     console.log(iterResult2); // { value: 'b', done: false }
     return asyncIterator.next();
    })
    .then(iterResult3 => {
      console.log(iterResult3); // { value: undefined, done: true }
    });

    从上面可以看出异步遍历器调用next方法返回一个promise,然后promise的状态变为resolve,然后调用then函数,执行then函数内的回调函数
    由于调用next方法返回的是一个promise对象,所以说可以放在await命令后面,代码如下

    async function f() {
     const asyncIterable = createAsyncIterable(['a', 'b']);
     const asyncIterator = asyncIterableSymbol.asyncIterator;
     console.log(await asyncIterator.next());
      // { value: 'a', done: false }
      console.log(await asyncIterator.next());
     // { value: 'b', done: false }
     console.log(await asyncIterator.next());
     // { value: undefined, done: true }
    }

    上面的代码接近于同步执行,但是我们想要所有的await基本上同时进行,可以有一下俩种表示

    const asyncGenObj = createAsyncIterable(['a', 'b']);
    const [{value: v1}, {value: v2}] = await Promise.all([
     asyncGenObj.next(), asyncGenObj.next()
    ]);
    console.log(v1, v2); // a b
    //第二种
    async function runner() {
      const writer = openFile('someFile.txt');
     writer.next('hello');
     writer.next('world');
     await writer.return();
    }
    runner();

    for await of

    我们都知道同步遍历器我们可以使用for of来遍历,但是异步的遍历器,我们使用for await of来遍历

    async function f() {
    for await (const x of createAsyncIterable(['a', 'b'])) {
     console.log(x);
      }
    }
    // a
    // b

    异步generator函数

    简单的说就是async与generator函数的结合,如下

    async function* gen() {
      yield 'hello';
    }
    const genObj = gen();
    genObj.next().then(x => console.log(x));
    // { value: 'hello', done: false }

    首先genObj.next()返回的是一个promise,然后调用then,执行then里面的函数,再看一个我认为比较重要的例子

    async function* readLines(path) {
    let file = await fileOpen(path);
    try {
      while (!file.EOF) {
      yield await file.readLine();
    }
    } finally {
      await file.close();
    }
    }

    我们可以看出异步generator函数,既有await也有yield,其中await命令用于将file.readLine()返回的结果输入到函数内,然后yield用于将输入到函数内的结果从函数输出


    在异步generator函数中的yield* 语句后面还可以跟一个异步的generator函数

    相关文章

      网友评论

          本文标题:async函数

          本文链接:https://www.haomeiwen.com/subject/yvmifftx.html