async的基本用法「建议收藏」

async的基本用法「建议收藏」1.async函数的基本形式2.async函数的返回值总是一个Promise无论async函数有无await操作,其总是返回一个Promise。1.没有显式return,相当于return

大家好,又见面了,我是你们的朋友全栈君。

1. async函数的基本形式

//函数声明
async function foo() {}

//函数表达式
const foo = async function () {};

//对象的方法
let obj = { async foo() {} };
obj.foo().then(...)

//Class 的方法
class Storage {
constructor() {
    this.cachePromise = caches.open('avatars');
}
async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
}
}

const storage = new Storage();
storage.getAvatar('jake').then(…);

//箭头函数
const foo = async () => {};

2. async函数的返回值总是一个Promise

无论async函数有无await操作,其总是返回一个Promise。

1. 没有显式return,相当于return Promise.resolve(undefined);
2. return非Promise的数据data,相当于return Promise.resolve(data);
3. return Promise, 会得到Promise对象本身

async总是返回Promise,因此,其后面可以直接调用then方法,
函数内部return返回的值,会成为then回调函数的参数
函数内部抛出的错误,会被then的第二个函数或catch方法捕获到

//正常返回值
async function f(){
    retrun 'hello world';
}

f().then(v => console.log(v));//hello world

//抛出错误
async function f(){
    throw new Error('出错了');
}

f().then(
    v => console.log(v),
    e => console.log(e) //Error: 出错了
)

3. await操作符的值

[rv] = await expression(expression可以是任何值,通常是一个promise)

expression是Promise,rv等于Promise兑现的值,若Promise被拒绝,则抛出异常,由catch捕获
expression是非Promise,会被转换为立即resolve的Promise,rv等于expression

await操作只能用在async函数中,否则会报错。

4. async就是generator和promise的语法糖

//generator写法
var gen = function* () {
  var f1 = yield readFile('/etc/fstab');
  var f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

//async写法
var asyncReadFile = async function () {
  var f1 = await readFile('/etc/fstab');
  var f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

async就是将 generator的 * 换成 async,将 yield 换成 await。

5. async对generator的改进

1. 内置执行器

Generator必须依靠执行器调用next方法来自动执行,例如co模块。而async函数自带执行器,可以自动执行。

2. 更好的语义

async和await分别表示异步和等待,语义更加明确

3. 适用性更强

co模块后面只能是Thunk函数或Promise对象,而await后面可以是Promise或基本数据类型(如:数字,字符串,布尔等)

4. 返回Promise,可以继续操作

async函数总是返回一个Promise对象,可以对其进行then调用,继续操作后面的数据,因此,
async函数完全可以看作是多个Promise合成一个Promise对象,而await命令就是内部的then调用。

6. async内部的并行调用

async配合await都是串行调用,但是若有并行调用,则应按照以下方式来写:

1. 变量分别接收Promise

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

2. 使用Promise.all

let [foo,bar] = await Promise.all([getFoo(),getBar()]);

Promise.all这种写法有缺陷,一个调用报错,会终止,这个不太符合并行调用的初衷。

3. 使用多个async函数

实际上,一个async函数内部包含的调用应该是强相关的,没有依赖关系的函数调用不应该放在一个async函数中,分开来逻辑更清晰。

4. 并行执行的一些写法

1. 不能再内部非async function中使用await

async function dbFuc(db) {
  let docs = [{}, {}, {}];
  // 报错,forEach的function是非async,不能使用await
  docs.forEach(function (doc) {
    await db.post(doc);
  });
}

//这里不需要 async
function dbFuc(db) { 
  let docs = [{}, {}, {}];
  // 可能得到错误结果,这样调用也不能得到正确的结果
  docs.forEach(async function (doc) {
    await db.post(doc);
  });
}

2. 循环调用await可以使用for循环或for of循环

//for of
async function dbFuc(db) {
  let docs = [{}, {}, {}];

  for (let doc of docs) {
    await db.post(doc);
  }
}

//map + Promise.all
async function dbFuc(db) {
  let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = await Promise.all(promises);
  console.log(results);
}

//map + for of
async function dbFuc(db) {
  let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = [];
  for (let promise of promises) {
    results.push(await promise);
  }
  console.log(results);
}

//for循环中去请求网页,若await操作成功,会break退出;若失败,会catch捕获,进入下一轮循环
const superagent = require('superagent');
const NUM_RETRIES = 3;

async function test() {
  let i;
  for (i = 0; i < NUM_RETRIES; ++i) {
    try {
      await superagent.get('http://google.com/this-throws-an-error');
      break;
    } catch(err) {}
  }
  console.log(i); // 3
}

test();

7. async的错误处理

使用try…catch进行包裹,例如:

async function myFunction() {
    try {
        await somethingThatReturnsAPromise();
    } catch (err) {
        console.log(err);
    }
}

如果仅仅对一部分错误进行处理或者忽略,可以局部的进行包裹,或者对单独的promise进行catch,例如:

async function myFunction() {
    await somethingThatReturnsAPromise().catch((err)=> {
            console.log(err);
    })
}

async function myFunction() {
    try{
        await somethingThatReturnsAPromise();
    }
    catch(e){}
    await somethingElse();
}

Promise的错误处理,推荐用async + await来写:

// 存值
createData(title, successBack, errorBack) {
    // 使用key保存数据
    storage.save({
        key: title,   
        data: 'true',
    }).then(successBack(), errorBack());
}

改写为

//存值
async createData1(title, successBack, errorBack) {
    try {
        // 使用key保存数据
        await storage.save({
            key: title,  
            data: 'true',
        });
        successBack()
    } catch (e) {
        errorBack()
    }
}

形式上更加清晰一些。

8. async函数的实现原理

async函数就是将执行器和Generator做为一个整体返回。

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

    })
}

spawn的实现

function spawn(genF) {
    /****
    * 返回的是一个promise
    */
    return new Promise(function(resolve, reject) {
        var gen=genF(); //运行Generator这个方法;
        /***
        * 执行下一步的方法
        * @param fn 一个调用Generator方法的next方法
        */
        function step(fn) {
            //如果有错误,则直接返回,不执行下面的await
            try {
            var next=fn();
            }catch (e){
            return reject(e)
            }
            //如果下面没有yield语句,即Generator的done是true
            if(next.done){
            return resolve(next.value);
            }
            Promise.resolve(next.value).then((val)=>{
                step(function(){ return gen.next(val) } )
            }).catch((e)=>{
                step(function(){ return gen.throw(e) } )
            })
        }
        step(function () {
            return gen.next();
        })
    });
}

 

 

 

参考:https://segmentfault.com/a/1190000008677697
     https://juejin.im/post/5b56837c6fb9a04fe0181555
   https://www.cnblogs.com/goloving/p/8013119.html
   https://blog.csdn.net/u011272795/article/details/80197481

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/154242.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Excel中的sumifs_理解和懂得的区别

    Excel中的sumifs_理解和懂得的区别SUMIF函数和SUMIFS函数都是EXCEL常用函数之一,同时这二个函数都是条件求和,只不过SUMIF函数是单条件求和,SUMIFS函数是多条件求和,其语法结构也是不同的。希望通过本经验能够使大家对

  • 软件激活成功教程教程2[通俗易懂]

    软件激活成功教程教程2[通俗易懂]第四章–调试器及相关工具入门在写这章之前,我看了一下看雪以往的教程。本来想参考一下,可忽然发现,写这样的一章,是一件非常愚蠢的事情,因为我觉的关于这些工具的使用教程。看雪教程中已经写的够详细的了,我并不认为你会看不懂。所以我不想做浪费时间的人,本章就此搁浅。推荐看《CrackTutorial2001》,推荐看《看雪论坛精华一、二、三、四》,推荐看《加密与解密--软件保护技术及完全解决方案》,

  • CoreOS裸机iso安装和相关配置

    CoreOS裸机iso安装和相关配置

  • 到底该不该用RTOS——rtos的优点

    到底该不该用RTOS——rtos的优点我现在要不要学习RTOS? 学习RTOS有什么好处? 我的项目要不要跑RTOS?······等等一些关于RTOS的问题,

  • ZigBee集成开发环境IAR安装

    一、Zigbee概述1.什么是ZigbeeZigBee是一种近距离、低复杂度的双向无线通信系统,主要用于距离短、功耗低、传输速率不高的电子设备之间进行数据传输,且具有低功耗、低成本、大容量、时延短、可靠性高以及网络拓扑结构灵活的特点。Zigbee本质就是无线设备之间的一种通信方式,类似于人和人之间用普通话交流,普通话就是一种通信方式。Zigbee,Zigbee通信方式,Zigbee协议说的都是一回事。Zigbee的主要作用是用来构建无线局域网。2.各通信方式的比较蓝牙:功耗比较低,组建网络节点数

  • jlink接口定义接stm32_图解Stm32使用jlink程序时jtag接口(SW和JTAG模式)的简化方法

    jlink接口定义接stm32_图解Stm32使用jlink程序时jtag接口(SW和JTAG模式)的简化方法用过STm32的人都知道stm32有两种常用程序的方法,用串口和jlink。串口方法和51差不多不多说,用jlink时接口引脚太多导致接口很大,很占pcb的面积,在此我就针对这个问题清晰的讲述下jlink程序时jtag接口的简化方法!希望对大家有用。!我实验的是jlinkv8和stm32f103rbt6!如果用jtag模式的话,需要接:jlink的第1脚(VDD)、第3脚(TRST对应stm32…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号