zoukankan      html  css  js  c++  java
  • 高阶Promise--async

    利用异步函数async,可以像写同步代码那样写基于Promise的代码,还可以让异步代码主线程.

    await某个Promise时,函数暂停执行,直到该Promise产生结果,并且暂停并不会重启主线程.

    async的工作方式:

    async function myFirstAsyncFunction(){
      try {
        const fulfilledValue = await promise;
      }
      catch (rejectedValue) {
        // ...
      }
    }
    

    示例: 通过fetch获取网络日志

    之前:

    function logFetch(url) {
      return fetch(url)
        .then(response => response.text())
        .then(text => {
          console.log(text);
        }).catch(err => {
          console.error('fetch failed', err)
        });
    }
    

    使用async之后:

    async function logFetch(url){
      try {
        const response = await fetch(url);
        console.log(await response.text());
      }
      catch (err) {
        console.error('fetch failed', err)
      }
    }
    

    使用 async 相较 promise,去掉了所有回调.

    示例: 流式传输响应

    在流式传输响应的同时,记录数据块日志,并返回数据块最终大小.

    之前:

    function getResponseSize(url){
      return fetch(url).then(response => {
        const reader = reponse.body.getReader();
        let total = 0;
    
        return reader.read().then(function processResult(result) {
            if (result.done) return total;
            
            const value = result.value;
            total += value.length;
            console.log('Received chunk', value);
        
            return reader.read().then(processResult);
        })
      });
    }
    

    这是一段精巧的代码,在 processResult 内部调用其自身来建立异步循环,看起来很只能,但是得盯着看上一会儿才能明白其作用.

    使用async之后:

    async function getResponseSize(url) {
      const response = await fetch(url);
      const reader = response.body.getReader();
      let result = await reader.read();
      let total = 0;
    
      while (!result.done) {
        const value = result.value;
        tatol += value.length;
        console.log('Received chunk', value);
        // get the next result
        result = await reader.read();
      }
      
      return total;
    }
    

    让人大有飘飘然的异步循环被替换成可靠却单调乏味的while循环,但简明性大幅提升.

    未来,将使用异步迭代器来将 while 循环替换成 for-of 循环,从而进一步提高代码简明性.

    其它使用async的场景,在剪头函数中,对象方法中,类方法中.类构造函数以及getter/setter方法中不能是异步的.

    弊端写法,过于循序.示例: 获取一系列网址并尽快按照正确顺序将其记录到日志中

    [不推荐]promise写法

    function logInOrder(urls) {
      // fetch all the URLs
      const textPromises = urls.map(url => {
        return fetch(url).then(response => response.text());
      });
      // log them in order
      textPromises.reduce((chain, textPromise) => {
        return chain.then(() => textPromise)
          .then(text => console.log(text));
      }, Promise.resolve());
    }
    

    上面还使用了智能的reduce来对Promise序列进行链接,但这种编码过于"智能"还是不要为好.

    使用async简单改写以上代码会让代码变得过于循序.

    [不推荐]async的过于循序写法

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

    代码简洁不少,但我们想要的第二次获取必须等到第一次获取完毕之后才能开始,执行效率比并行执行获取的Promise低得多.

    进一步使用async改写,使其并行效率高:

    async function logInOrder(urls) {
      // fetch all the URLs in parallel
      const textPromises = urls.map(async url => {
        const response = await fetch(url);
        return response.text();
      });
    
      // log them in sequence
      for (const textPromise of textPromises) {
        console.log(await textPromise);
      }
    }
    

    以并行方式获取和读取网址,但将"智能的"reduce替换成了标准的单调的乏味的但可读性强的for循环.

    使用generator生成器进行polyfill

    原先异步代码:

    async function slowEcho(val) {
      await wait(1000);
      return val;
    }
    

    进行polyfill:

    const slowEcho = createAsyncFunction(function*(val){
      yield wait(1000);
      return val;
    })
    

    将生成器(function*)传给createAsyncFuntion,并使用yield来代替await.

    babel里polyfill await的工作方式

    简单async代码:

    async function logFetch(url) {
      try {
        const response = await fetch(url);
        console.log(await response.text());
      }
      catch (err) {
        console.log('fetch failed', err);
      }
    }
    

    转换后:

    function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
    
    function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
    
    function logFetch(_x) {
      return _logFetch.apply(this, arguments);
    }
    
    function _logFetch() {
      _logFetch = _asyncToGenerator(function* (url) {
        try {
          const response = yield fetch(url);
          console.log(yield response.text());
        } catch (err) {
          console.log('fetch failed', err);
        }
      });
      return _logFetch.apply(this, arguments);
    }
    

    在非async函数中调用async函数

    async function wait() {
      await new Promise((resolve => setTimeout(resolve, 1000));
      return 10;
    }
    
    function f(){
      wait().then(result => alert(result));
    }
    

    把async函数当做Promise函数用即可.

  • 相关阅读:
    HDU 1874 畅通工程续 (Dijkstra , Floyd , SPFA, Bellman_Ford 四种算法)
    HDU Wooden Sticks
    HDU 3664 Permutation Counting
    javascript DOM添加元素,使用节点属性
    SQL server查询数据类型为ntext是空或NULL值
    TSQL Pivot Tables(行列转换) in SQL Server 2005/2008
    ASP.NET 3.5(c#)区域化设置(LCID)
    Sql 脚本导入EXCEL数据
    asp.net 3.5 csharp 实现事务
    asp.net3.5 csharp: How to show HTML content in calendar tooltip?
  • 原文地址:https://www.cnblogs.com/hencins/p/15205272.html
Copyright © 2011-2022 走看看