亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

異步發(fā)展流程 —— 異步編程的終極大招 async/await

zhangfaliang / 1224人閱讀

摘要:簡(jiǎn)介指的是兩個(gè)關(guān)鍵字,是引入的新標(biāo)準(zhǔn),關(guān)鍵字用于聲明函數(shù),關(guān)鍵字用來(lái)等待異步必須是操作,說(shuō)白了就是的語(yǔ)法糖。最后希望大家在讀過(guò)異步發(fā)展流程這個(gè)系列之后,對(duì)異步已經(jīng)有了較深的認(rèn)識(shí),并可以在不同情況下游刃有余的使用這些處理異步的編程手段。

閱讀原文


前言

這篇文章是異步發(fā)展流程系列的最后一篇,可能會(huì)涉及 Promise、Generators、co 等前置知識(shí),如果對(duì)這些不是很了解可以看這個(gè)系列的前三篇:

異步發(fā)展流程 —— Promise 的基本使用

異步發(fā)展流程 —— 手寫(xiě)一個(gè)符合 Promise/A+ 規(guī)范的 Promise

異步發(fā)展流程 —— Generators + co 讓異步更優(yōu)雅

如果已經(jīng)具備這些前置知識(shí),那我們繼續(xù)看看今天的主角,JavaScript 異步編程的終極大招 async/await。

async/await 簡(jiǎn)介

async/await 指的是兩個(gè)關(guān)鍵字,是 ES7 引入的新標(biāo)準(zhǔn),async 關(guān)鍵字用于聲明 async 函數(shù),await 關(guān)鍵字用來(lái)等待異步(必須是 Promise)操作,說(shuō)白了 async/await 就是 Generators + co 的語(yǔ)法糖。

async/await 和 Generators + co 的寫(xiě)法非常的相似,只是把用于聲明 Generator 函數(shù)的 * 關(guān)鍵字替換成了 async 并寫(xiě)在了 function 關(guān)鍵字的前面,把 yield 關(guān)鍵字替換成了 await;另外,async 函數(shù)是基于 Promise 的,await 關(guān)鍵字后面等待的異步操作必須是一個(gè) Promise 實(shí)例,當(dāng)然也可以是原始類型的值,只不過(guò)這時(shí)的執(zhí)行效果等同于同步,與 Generator 不同的是,await 關(guān)鍵字前可以使用變量去接收這個(gè)正在等待的 Promise 實(shí)例執(zhí)行后的結(jié)果。

async 函數(shù)的基本用法

async 函數(shù)返回一個(gè) Promise 實(shí)例,可以使用 then 方法添加回調(diào)函數(shù)。當(dāng)函數(shù)執(zhí)行的時(shí)候,只要遇到 await 就會(huì)等待,直到 await 后面的同步或異步操作完成,再接著執(zhí)行函數(shù)體內(nèi)后面的語(yǔ)句。

1、async 函數(shù)聲明

async 的聲明方式大概有以下幾種:

//  async 函數(shù)聲明
// 函數(shù)聲明
async function fn() {}

// 函數(shù)表達(dá)式
const fn = async function() {};

// 箭頭函數(shù)
const fn = async () => {};

// 作為對(duì)象的方法
let obj = {
    async fn() {}
};

// 作為 class 的方法
class Person(name) {
    constructor () {
        this.name = name;
    }
    async getName() {
        const name = await this.name;
        return name;
    }
}

在上一篇介紹 Generators + co 的文章中我們舉了一個(gè)例子,使用 NodeJS 的 fs 模塊連續(xù)異步讀文件,第一個(gè)文件名為 a.txt,讀到的內(nèi)容為 b.txt,作為要讀的第二個(gè)文件的文件名,繼續(xù)讀 b.txt 后將讀到的內(nèi)容 “Hello world” 打印出來(lái)。

我們來(lái)使用 async/await 的方式來(lái)實(shí)現(xiàn)一下:

// async 函數(shù)實(shí)現(xiàn)文件讀取
// 引入依賴
const fs = require("fs");
const util = require("util");

// 將 fs.readFile 轉(zhuǎn)換成 Promise
const readFile = util.promisify(fs.readFile);

// 聲明 async 函數(shù)
async function read(file) {
    let aData = await readFile(file, "utf8");
    let bData = await readFile(aData, "utf8");
    return bData;
}

// 調(diào)用 async 函數(shù)
read("a.txt").then(data => {
    console.log(data); // Hello world
});

其實(shí)對(duì)比上一篇文章 Generator 的案例,與 Generator 函數(shù)一樣,寫(xiě)法像同步,執(zhí)行是異步,不同的是我們即沒(méi)有手動(dòng)調(diào)用 next 方法,也沒(méi)有借助 co 庫(kù),其實(shí)是 async 函數(shù)內(nèi)部集成了類似于 co 的執(zhí)行器,幫我們?cè)诋惒酵瓿珊笞詣?dòng)向下執(zhí)行代碼,所以說(shuō) async/await 是 Generators + co 的語(yǔ)法糖。

2、async 函數(shù)錯(cuò)誤處理

async 函數(shù)內(nèi)部如果執(zhí)行錯(cuò)誤可以有三種方式進(jìn)行錯(cuò)誤處理:

await 后面的 Promise 實(shí)例使用 then 方法錯(cuò)誤的回調(diào)或 catch 方法進(jìn)行錯(cuò)誤處理;

如果有多個(gè) await,可以在 async 函數(shù)執(zhí)行完后使用 catch 方法統(tǒng)一處理;

由于 async 內(nèi)部代碼是同步的寫(xiě)法,多個(gè) await 的情況也可以使用 try...catch... 進(jìn)行處理。

需要注意的是,如果在 async 函數(shù)內(nèi)部使用了 try...catch... 又在函數(shù)執(zhí)行完后使用了 catch,錯(cuò)誤會(huì)優(yōu)先被同步的 try...catch... 捕獲到,后面的 catch 就不會(huì)再捕獲了。

// async 函數(shù)異常捕獲
// 第一種
async function fn() {
    let result = await Promise.reject("error").catch(err => {
        console.log(err);
    });
}

fn(); // error

// 第二種
async function fn() {
    try {
        let val1 = await Promise.reject("error");
        let val2 = await Promise.resolve("success");
    } catch (e) {
        console.log(e);
    }
}

fn(); // error

// 第三種
async function fn() {
    let val1 = await Promise.resolve("success");
    let val2 = await Promise.reject("error");
}

fn().catch((err => console.log(err))); // error
3、await 異步并發(fā)

async 函數(shù)中,如果有多個(gè) await 互不依賴,這種情況下如果執(zhí)行一個(gè),等待一個(gè)完成,再執(zhí)行一個(gè),再等待完成,這樣是很浪費(fèi)性能的,所以我們要把這些異步操作同時(shí)觸發(fā)。

假設(shè)我們異步讀取兩個(gè)文件,且這兩個(gè)文件不相關(guān),我可以使用下面的方式來(lái)實(shí)現(xiàn):

// await 異步并發(fā)
// 前置
const fs = require("fs");
const util = require("util");
const readFile = util.promisify(fs.readFile);

// 需要改進(jìn)的 async 函數(shù)
async function fn() {
    let aData = await readFile("a.txt", "utf8");
    let bData = await readFile("b.txt", "utf8");
    return [aData, bData];
}

fn();

// 在 async 函數(shù)外部觸發(fā)異步
let aDataPromise = readFile("a.txt", "utf8");
let bDataPromise = readFile("b.txt", "utf8");

async function fn() {
    let aData = await aDataPromise;
    let bData = await bDataPromise;
    return [aData, bData];
}

fn();

// 使用 Promise.all
async function fn() {
    let dataArr = await Promise.all(
        readFile("a.txt", "utf8"),
        readFile("a.txt", "utf8")
    );
    return dataArr;
}

fn();
4、使用 async/await 的注意點(diǎn)

使用 async/await 應(yīng)注意以下幾點(diǎn):

對(duì) await 習(xí)慣性錯(cuò)誤處理;

await 命令后互不依賴的異步應(yīng)同時(shí)觸發(fā);

async 函數(shù)中,函數(shù)的執(zhí)行上/下文發(fā)生變化時(shí),不能使用 await(如使用 forEach 循環(huán)的回調(diào)中)。

針對(duì)第一點(diǎn),在 async 函數(shù)中 await 命令后面大多情況下是 Promise 異步操作,運(yùn)行結(jié)果可能出現(xiàn)錯(cuò)誤并調(diào)用 reject 函數(shù),最好對(duì)這個(gè) await 語(yǔ)句進(jìn)行錯(cuò)誤處理,具體方式參照 async 函數(shù)基本用法中關(guān)于錯(cuò)誤處理的內(nèi)容。

針對(duì)第二點(diǎn),如果兩個(gè)或多個(gè) await 命令后的異步操作沒(méi)有依賴關(guān)系,執(zhí)行時(shí),需先觸發(fā)第一個(gè),等待異步完成,再觸發(fā)第二個(gè),再等異步完成,依次類推,這樣比較耗時(shí),性能不好,所以應(yīng)該將這些異步操作同時(shí)觸發(fā),觸發(fā)方式參照 async 函數(shù)基本用法中的 await 異步并發(fā)的內(nèi)容。

針對(duì)第三點(diǎn),如果聲明一個(gè) async 函數(shù)并傳入一個(gè)數(shù)組,數(shù)組里面存儲(chǔ)的都是 Promise 實(shí)例,若使用 forEach 循環(huán)數(shù)組,由于函數(shù)的執(zhí)行上/下文發(fā)生了變化,此時(shí)使用 await 命令會(huì)報(bào)錯(cuò)。

// 循環(huán)內(nèi)使用 await
// 創(chuàng)建 Promise 實(shí)例
let p1 = Promise.resolve("p1 success");
let p2 = Promise.resolve("p2 success");
let p3 = Promise.resolve("p3 success");


// async 函數(shù)
async function fn(promises) {
    promise.forEach(function (promise) {
        await promise;
    });
}

fn([p1, p2, p3]); // 執(zhí)行時(shí)報(bào)錯(cuò)


// 修改方式
async function fn(promises) {
    for(let i = 0; i < promises.length; i++) {
        await pormises[i];
    }
}

fn([p1, p2, p3]); // 正常執(zhí)行


總結(jié)

async/await 的實(shí)現(xiàn)原理,其實(shí)就是在 async 函數(shù)內(nèi)部邏輯映射成了 Generator 函數(shù)并集成了一個(gè)類似于 co 的執(zhí)行器,所以我們使用 async/await 的時(shí)候,代碼更簡(jiǎn)潔,沒(méi)有了自己觸發(fā)遍歷器的 next 或調(diào)用 co 充當(dāng)執(zhí)行器的過(guò)程,只需要關(guān)心 async 函數(shù)的內(nèi)部邏輯就可以了,因?yàn)閷?xiě)法與同步相同,更提高了代碼的可讀性,所以說(shuō) async/await 是異步編程的終極大招。

由于 async/await 是 ES7 規(guī)范,在瀏覽器端的支持并不是那么的友好,所以現(xiàn)在這種寫(xiě)法多用在 NodeJS 的異步操作當(dāng)中,在 NodeJS 框架 Koa 2.x 版本得到廣泛應(yīng)用。

最后希望大家在讀過(guò)異步發(fā)展流程這個(gè)系列之后,對(duì) JavaScript 異步已經(jīng)有了較深的認(rèn)識(shí),并可以在不同情況下游刃有余的使用這些處理異步的編程手段。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/98279.html

相關(guān)文章

  • ES6—Async異步編程(11)

    摘要:所以異步編程對(duì)語(yǔ)言太重要。異步編程我們就以用戶注冊(cè)這個(gè)特別常見(jiàn)的場(chǎng)景為例,講講異步編程。這種層層嵌套被稱為回調(diào)地獄。相比回調(diào)函數(shù)而言,代碼可讀性更高,代碼的執(zhí)行順序一目了然。函數(shù)內(nèi)部語(yǔ)句返回的值,會(huì)成為方法回調(diào)函數(shù)的參數(shù)。 單線程是Javascript語(yǔ)言最本質(zhì)的特性之一,Javascript引擎在運(yùn)行js代碼的時(shí)候,同一個(gè)時(shí)間只能執(zhí)行單個(gè)任務(wù)。 這種模式的好處是實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單,執(zhí)行...

    chengjianhua 評(píng)論0 收藏0
  • js異步解決方案 --- 回調(diào)函數(shù) vs promise vs generater/yield vs

    摘要:異步流程管理說(shuō)白了就是為了解決回調(diào)地獄的問(wèn)題。對(duì)象代表一個(gè)異步操作,有三種狀態(tài)進(jìn)行中已成功和已失敗。如果改變已經(jīng)發(fā)生了,你再對(duì)對(duì)象添加回調(diào)函數(shù),也會(huì)立即得到這個(gè)結(jié)果。執(zhí)行函數(shù)后返回的是一個(gè)遍歷器對(duì)象,可以依次遍歷函數(shù)內(nèi)部的每一個(gè)狀態(tài)。 javascript -- 深度解析異步解決方案 高級(jí)語(yǔ)言層出不窮, 然而唯 js 鶴立雞群, 這要說(shuō)道js的設(shè)計(jì)理念, js天生為異步而生, 正如布道...

    0xE7A38A 評(píng)論0 收藏0
  • ES6-7

    摘要:的翻譯文檔由的維護(hù)很多人說(shuō),阮老師已經(jīng)有一本關(guān)于的書(shū)了入門(mén),覺(jué)得看看這本書(shū)就足夠了。前端的異步解決方案之和異步編程模式在前端開(kāi)發(fā)過(guò)程中,顯得越來(lái)越重要。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(shū)(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書(shū)的目的是以目前還在制定中的ECMASc...

    mudiyouyou 評(píng)論0 收藏0
  • 【全文】狼叔:如何正確學(xué)習(xí)Node.js

    摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類中文書(shū)籍收錄并推薦地址,以后在倉(cāng)庫(kù)里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡(jiǎn)介現(xiàn)在,越來(lái)越多的科技公司和開(kāi)發(fā)者開(kāi)始使用開(kāi)發(fā)各種應(yīng)用。 說(shuō)明 2017-12-14 我發(fā)了一篇文章《沒(méi)用過(guò)Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車的還坐過(guò)站了。大家可以很...

    Edison 評(píng)論0 收藏0
  • 【全文】狼叔:如何正確學(xué)習(xí)Node.js

    摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類中文書(shū)籍收錄并推薦地址,以后在倉(cāng)庫(kù)里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡(jiǎn)介現(xiàn)在,越來(lái)越多的科技公司和開(kāi)發(fā)者開(kāi)始使用開(kāi)發(fā)各種應(yīng)用。 說(shuō)明 2017-12-14 我發(fā)了一篇文章《沒(méi)用過(guò)Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車的還坐過(guò)站了。大家可以很...

    fengxiuping 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<