ES6 异步编程解决方案 之 Async

一、async 函数的基本用法

  • async 函数返回一个 Promise 对象,可以使用 thencatch 方法 添加回调函数
  • async 函数执行时,一旦遇到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句 【异步函数 同步执行】
  • async 函数有很多种形式:
// 函数声明
async function foo() {}

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

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

// Class 的方法
class Storage {
  constructor() {
    this.cachePromise = caches.open(‘avatars‘);
  }

  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}

// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)
  • 示例: 指定多少毫秒后输出一个值
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);

// 上面代码指定 50 毫秒以后,输出 hello world

二、async 语法

1. async 函数

  • async 函数的返回值 是 Promise 对象 (可调用 thencatch 方法)
  • async 函数内部抛出错误,会导致返回的 Promise 对象变为 reject 状态
  • async 函数的回调方法 thencatch 的参数
    • async 函数内部 return 关键字返回的值,会 作为 thencatch 方法的参数
    • async 函数的返回的 Promise 对象 状态为 resolve 时,函数内部 若没有返回值,thencatch 方法的参数 为 undefined;调用 then 方法
    • async 函数的返回的 Promise 对象 状态为 reject 时,函数内部 若没有返回值,thencatch 方法的参数 为 错误对象;调用 catch 方法
async function f() {
    return await Promise.resolve(123);
}

f().then(v => console.log(v));  // 123
async function f() {
    await Promise.resolve(123);
}

f().then(v => console.log(v));  // undefined
async function f() {
  throw new Error(‘出错了‘);
}

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

2. await 关键字

  • await 关键字 只能在 async 函数中使用: await 后面 如果跟异步函数,程序执行时会等 await 后面的 异步函数执行完之后,再执行 后面的代码 【异步函数 同步执行】
  • 正常情况下,await 命令后面是一个 Promise 对象;如果不是,会转成 Promise 对象,并立即 resolve
// 只要有一个 `await` 后面的函数执行错误,程序就会停止执行代码

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

f().then(
    (result) => {
        console.log(result);
    },
    (e) => {
        console.log(e);
    }
);      // 出错了

三、async 应用

1. 一个 async 函数中,有多个 await 关键字:使用 try..catch( ) 避免程序终止

  • 场景: 只要有一个 await 后面的函数执行错误,程序就会停止执行代码; async 函数返回的 Promise 对象的状态为 reject
  • 解决方案:
    • 方案 1:使用 try...catch() 把有可能出错的 操作放到 try 语句中
    • 方案 2:await 后面的 Promise 对象再跟一个 catch 方法,处理前面可能出现的错误
// 解决方案 1:try...catch() 即使有一个异步操作失败,也不终止程序

async function f() {
    try {
        await Promise.reject(‘出错了‘);
    } catch(e) {
        console.log(e);
    }

    return await Promise.resolve(‘hello world‘);
}

f().then(v => console.log(v))
// hello world
// 解决方案 2:catch() 即使有一个异步操作失败,也不终止程序

async function f() {
    await Promise.reject(‘出错了‘)
        .catch(e => console.log(e));
    return await Promise.resolve(‘hello world‘);
}

f().then(v => console.log(v))
// 出错了
// hello world

2. 一个 async 函数中,有多个 await 关键字:使 await 后面的异步操作 同时执行

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

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

3. 使用 try...catch() 结合 asyncawait 实现 ajax 请求轮询

const NUM_RETRIES = 3;

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

ajaxRequest();

四、async for await...of ---> 异步遍历

  • 遍历时,有一个异步请求报错,都会导致程序终止;所以,结合 try...catch() 解决此类问题
async function () {
    try {
        for await (const x of createRejectingIterable()) {
            console.log(x);
        }
    }
    catch (e) {
        console.error(e);
    }
}

五、async 与 其他异步解决方案的 比较

  • Promise: 比回调函数的写法大大改进,但是一眼看上去,代码完全都是 Promise 的 API(then、catch等等),操作本身的语义反而不容易看出来
  • Generator: 语义比 Promise 写法更清晰,需要有 任务运行器,自动执行 Generator 函数;但偏底层的写法
  • async: Generator 函数的语法糖,封装了 Generator 的底层机制 ,实现最简洁,最符合语义;

原文地址:https://www.cnblogs.com/zxvictory/p/8548443.html

时间: 2024-08-28 07:41:24

ES6 异步编程解决方案 之 Async的相关文章

C#基础系列——异步编程初探:async和await

前言:前面有篇从应用层面上面介绍了下多线程的几种用法,有博友就说到了async, await等新语法.确实,没有异步的多线程是单调的.乏味的,async和await是出现在C#5.0之后,它的出现给了异步并行变成带来了很大的方便.异步编程涉及到的东西还是比较多,本篇还是先介绍下async和await的原理及简单实现. C#基础系列目录: C#基础系列——Linq to Xml读写xml C#基础系列——扩展方法的使用 C#基础系列——序列化效率比拼 C#基础系列——反射笔记 C#基础系列——At

[C#]剖析异步编程语法糖: async和await

一.难以被接受的async 自从C#5.0,语法糖大家庭又加入了两位新成员: async和await. 然而从我知道这两个家伙之后的很长一段时间,我甚至都没搞明白应该怎么使用它们,这种全新的异步编程模式对于习惯了传统模式的人来说实在是有些难以接受,不难想象有多少人仍然在使用手工回调委托的方式来进行异步编程.C#中的语法糖非常多,从自动属性到lock.using,感觉都很好理解很容易就接受了,为什么偏偏async和await就这么让人又爱又恨呢? 我想,不是因为它不好用(相反,理解了它们之后是非常

nodejs学习笔记 —— 异步编程解决方案

在js或者node编程中,由于异步的频繁和广度使用,使得回调和嵌套的深度导致编程的体验遇到一些挑战,如果写出优雅和好看的代码,本文主要针对异步编程的主流方案做一些总结 1.事件发布/订阅模式 事件监听器模式是一种广泛用于异步编程的模式, 是回调函数的事件化,又称发布/订阅模式, node自身提供events模块,是该模式的一个简单实现. EventPorxy 2.promise/deferrd模式 在2009年被Kris Zyp抽象为一个提议草案,发布在CommonJS规范中, 目前,Commo

异步编程解决方案之事件发布/订阅模式

时间监听模式是广泛用于异步编程的模式,是回调函数的事件化,又称不发订阅模式. nodejs的events模块就是发布订阅模式的一个简单实现,不存在preventDefault,stopPropagation,stopImmediatePropagation,等控制事件传递的方法. 它具有addListner/on(),once(),removeListner(),removeAllLisetner()和emit等基础监听事件方法. 事件发布/订阅十分简单,如下: //订阅 emitter.on(

javascript的异步编程解决方案收集

缘起 没理解js异步的同学看下面的例子: for (var i = 0; i < 5; i++) { //模拟一个异步操作 setTimeout(() => { console.log(i); }, 1000); } 我们想要的结果是:0,1,2,3,4 结果却出乎意料:5,5,5,5,5 分析 js的特点就是单线程异步非堵塞.需要好好理解这句话:js对于异步操作,不会停下来等待上一个异步操作完成,才进行下一个异步操作. 如果要达到顺序执行,只能用回调:也就是上一个异步操作完成时,再调用下一个

异步编程解决方案

事件发布/订阅模式 promise/deferrd模式 流程控制模式 事件发布/订阅模式 事件监听器模式是异步回调的事件化,又称发布订阅/模式 node核心模块events 方法 addListener/on once removeListener removeAllListeners emit 简单操作 let events = require('events') let request = require('http').request let emit = new events.Event

es6异步编程 Promise 讲解 --------各个优点缺点总结

//引入模块 let fs=require('fs'); //异步读文件方法,但是同步执行 function read(url) { //new Promise 需要传入一个executor 执行器 //executor需要传入两个函数 resolve reject return new Promise((resolve,reject)=>{ fs.readFile(url,'utf8',function (err,data) { if(err){ reject(err) }else{ reso

异步编程解决方案之Promise/Deferred

Promise三种状态:未完成.完成态.失败态 var events = require('events'); var util = require('util'); var EventEmitter = events.EventEmitter; var Promise = function () { EventEmitter.call(this); } util.inherits(Promise, EventEmitter); Promise.prototype.then = function

JavaScript学习--Item27 异步编程异常解决方案

1.JavaScript异步编程的两个核心难点 异步I/O.事件驱动使得单线程的JavaScript得以在不阻塞UI的情况下执行网络.文件访问功能,且使之在后端实现了较高的性能.然而异步风格也引来了一些麻烦,其中比较核心的问题是: 1.函数嵌套过深 JavaScript的异步调用基于回调函数,当多个异步事务多级依赖时,回调函数会形成多级的嵌套,代码变成 金字塔型结构.这不仅使得代码变难看难懂,更使得调试.重构的过程充满风险. 2.异常处理 回调嵌套不仅仅是使代码变得杂乱,也使得错误处理更复杂.这