zoukankan      html  css  js  c++  java
  • ES8之async/await学习随笔

    详细学习参考文档: 阮一峰老师的博客,覆盖知识点ES6/7/8/9,本篇学习笔记对阮老师的关于async/await文档中的知识点进行分点总结

    在ES8中加入async/await新特性后,很明显带来的好处是避免回调地狱,代码更加优雅,可读性远远提升。

    语法

    async函数的语法规则总体上比较简单,难点是错误处理机制。语法总结主要分为以下几点:

    1.async函数返回一个 Promise 对象。async函数内部return语句返回的值,会成为then方法回调函数的参数。

    async function f() {
      return 'hello world';
    }
    
    f().then(v => console.log(v))
    // "hello world"
    
    

    2.async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。

    async function fun() {
      throw new Error('啊,出错啦');
    }
    
    fun().then(
      v => console.log(v),
      e => console.log(e)
    )
    // Error: 啊,出错啦
    

    3.async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。

    async function getTitle(url) {
      let response = await fetch(url);
      let html = await response.text();
      return html.match(/<title>([sS]+)</title>/i)[1];
    }
    getTitle('https://tc39.github.io/ecma262/').then(console.log)
    // "ECMAScript 2017 Language Specification"
    

    4.正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。

    async function f() {
      // 等同于
      // return 123;
      return await 123;
    }
    
    f().then(v => console.log(v))
    // 123
    

    5.另一种情况是,await命令后面是一个thenable对象(即定义then方法的对象),那么await会将其等同于 Promise 对象。

    class Sleep {
      constructor(timeout) {
        this.timeout = timeout;
      }
      then(resolve, reject) {
        const startTime = Date.now();
        setTimeout(
          () => resolve(Date.now() - startTime),
          this.timeout
        );
      }
    }
    
    (async () => {
      const actualTime = await new Sleep(1000);
      console.log(actualTime);
    })();
    

    6.await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到。

    async function f() {
      await Promise.reject('出错了');
    }
    
    f()
    .then(v => console.log(v))
    .catch(e => console.log(e))
    // 出错了
    

    7.任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。

    async function f() {
      await Promise.reject('出错了');
      await Promise.resolve('hello world'); // 不会执行
    }
    

    错误处理

    1.捕获整个async/await函数的错误

    async function charCountAdd(data1, data2) {
        const d1=await charCount(data1);
        const d2=await charCount(data2);
        return d1+d2;
    }
    charCountAdd('Hello','Hi')
        .then(console.log)
        .catch(console.log);//捕捉整个async/await函数的错误
    

    这种方式可以捕捉整个charCountAdd运行过程中出现的错误,错误可能是由charCountAdd本身产生的,也可能是由对data1的计算中或data2的计算中产生的。

    2.捕捉单个的await表达式的错误

    async function charCountAdd(data1, data2) {
        const d1=await charCount(data1)
            .catch(e=>console.log('d1 is null'));
        const d2=await charCount(data2)
            .catch(e=>console.log('d2 is null'));
        return d1+d2;
    }
    charCountAdd('Hello','Hi')
        .then(console.log)
        .catch(console.log);//捕捉整个async/await函数的错误
    

    通过这种方式可以捕捉每一个await表达式的错误,如果既要捕捉每一个await表达式的错误,又要捕捉整个charCountAdd函数的错误,可以在调用charCountAdd的时候加个catch。

    3.同时捕捉多个的await表达式的错误

    async function charCountAdd(data1, data2) {
        let d1,d2;
        try {
            d1=await charCount(data1);
            d2=await charCount(data2);
        }catch (e){
            console.log('d1 is null');
        }
        return d1+d2;
    }
    charCountAdd('Hello','Hi')
        .then(console.log);
    
    function charCount(data) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(data.length);
            }, 1000);
        });
    }
    

    async/await的几种应用场景

    1.获取异步函数的返回值,异步函数本身会返回一个Promise,所以我们可以通过then来获取异步函数的返回值。

    async function charCountAdd(data1, data2) {
        const d1=await charCount(data1);
        const d2=await charCount(data2);
        return d1+d2;
    }
    charCountAdd('Hello','Hi').then(console.log);//通过then获取异步函数的返回值。
    function charCount(data) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(data.length);
            }, 1000);
        });
    }
    

    2.async/await在并发场景中的应用

    对于上述的例子,我们调用await两次,每次都是等待1秒一共是2秒,效率比较低,而且两次await的调用并没有依赖关系,那能不能让其并发执行呢,答案是可以的,接下来我们通过Promise.all来实现await的并发调用。

    async function charCountAdd(data1, data2) {
        const [d1,d2]=await Promise.all([charCount(data1),charCount(data2)]);
        return d1+d2;
    }
    charCountAdd('Hello','Hi').then(console.log);
    function charCount(data) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(data.length);
            }, 1000);
        });
    }
    

    实现原理

    async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。

    async function fn(args) {
      // ...
    }
    
    // 等同于
    
    function fn(args) {
      return spawn(function* () {
        // ...
      });
    }
    

    spawn函数的实现

    function spawn(genF) {
      return new Promise(function(resolve, reject) {
        const gen = genF();
        function step(nextF) {
          let next;
          try {
            next = nextF();
          } catch(e) {
            return reject(e);
          }
          if(next.done) {
            return resolve(next.value);
          }
          Promise.resolve(next.value).then(function(v) {
            step(function() { return gen.next(v); });
          }, function(e) {
            step(function() { return gen.throw(e); });
          });
        }
        step(function() { return gen.next(undefined); });
      });
    }
    
  • 相关阅读:
    108. Convert Sorted Array to Binary Search Tree
    How to check if one path is a child of another path?
    Why there is two completely different version of Reverse for List and IEnumerable?
    在Jenkins中集成Sonarqube
    如何查看sonarqube的版本 how to check the version of sonarqube
    Queue
    BFS广度优先 vs DFS深度优先 for Binary Tree
    Depth-first search and Breadth-first search 深度优先搜索和广度优先搜索
    102. Binary Tree Level Order Traversal 广度优先遍历
    How do I check if a type is a subtype OR the type of an object?
  • 原文地址:https://www.cnblogs.com/fe-linjin/p/10694665.html
Copyright © 2011-2022 走看看