国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

細(xì)說(shuō)JS異步發(fā)展歷程

RiverLi / 968人閱讀

摘要:參考文章珠峰架構(gòu)課墻裂推薦細(xì)說(shuō)異步函數(shù)發(fā)展歷程異步編程謝謝各位小伙伴愿意花費(fèi)寶貴的時(shí)間閱讀本文,如果本文給了您一點(diǎn)幫助或者是啟發(fā),請(qǐng)不要吝嗇你的贊和,您的肯定是我前進(jìn)的最大動(dòng)力。

知其然知其所以然,首先了解三個(gè)概念:

1.什么是同步?

所謂同步,就是在發(fā)出一個(gè)"調(diào)用"時(shí),在沒(méi)有得到結(jié)果之前,該“調(diào)用”就不返回。但是一旦調(diào)用返回,就得到返回值了。換句話說(shuō),就是由“調(diào)用者”主動(dòng)等待這個(gè)“調(diào)用”的結(jié)果。此調(diào)用執(zhí)行完之前,阻塞之后的代碼執(zhí)行。

2.什么是異步?

"調(diào)用"在發(fā)出之后,這個(gè)調(diào)用就直接返回了,所以沒(méi)有返回結(jié)果。換句話說(shuō),當(dāng)一個(gè)異步過(guò)程調(diào)用發(fā)出后,調(diào)用者不會(huì)立刻得到結(jié)果。而是在"調(diào)用"發(fā)出后,"被調(diào)用者"通過(guò)狀態(tài)、通知來(lái)通知調(diào)用者,或通過(guò)回調(diào)函數(shù)處理這個(gè)調(diào)用。異步調(diào)用發(fā)出后,不影響后面代碼的執(zhí)行。

3.JavaScript 中為什么需要異步?

首先我們知道JavaScript是單線程的(即使新增了webworker,但是本質(zhì)上JS還是單線程)。同步代碼意味著什么呢?意味著有可能會(huì)阻塞,當(dāng)我們有一個(gè)任務(wù)需要時(shí)間較長(zhǎng)時(shí),如果使用同步方式,那么就會(huì)阻塞之后的代碼執(zhí)行。而異步則不會(huì),我們不會(huì)等待異步代碼的之后,繼續(xù)執(zhí)行異步任務(wù)之后的代碼。

更多優(yōu)質(zhì)文章可戳: https://github.com/YvetteLau/...

概念了解完了,我們就要進(jìn)入今天的正題了。首先大家思考一下:平時(shí)在工作中,主要使用了哪些異步解決方案,這些異步方案有什么優(yōu)缺點(diǎn)?

異步最早的解決方案是回調(diào)函數(shù),如事件的回調(diào),setInterval/setTimeout中的回調(diào)。但是回調(diào)函數(shù)有一個(gè)很常見(jiàn)的問(wèn)題,就是回調(diào)地獄的問(wèn)題(稍后會(huì)舉例說(shuō)明);

為了解決回調(diào)地獄的問(wèn)題,社區(qū)提出了Promise解決方案,ES6將其寫(xiě)進(jìn)了語(yǔ)言標(biāo)準(zhǔn)。Promise一定程度上解決了回調(diào)地獄的問(wèn)題,但是Promise也存在一些問(wèn)題,如錯(cuò)誤不能被try catch,而且使用Promise的鏈?zhǔn)秸{(diào)用,其實(shí)并沒(méi)有從根本上解決回調(diào)地獄的問(wèn)題,只是換了一種寫(xiě)法。

ES6中引入 Generator 函數(shù),Generator是一種異步編程解決方案,Generator 函數(shù)是協(xié)程在 ES6 的實(shí)現(xiàn),最大特點(diǎn)就是可以交出函數(shù)的執(zhí)行權(quán),Generator 函數(shù)可以看出是異步任務(wù)的容器,需要暫停的地方,都用yield語(yǔ)句注明。但是 Generator 使用起來(lái)較為復(fù)雜。

ES7又提出了新的異步解決方案:async/await,async是 Generator 函數(shù)的語(yǔ)法糖,async/await 使得異步代碼看起來(lái)像同步代碼,異步編程發(fā)展的目標(biāo)就是讓異步邏輯的代碼看起來(lái)像同步一樣。

回調(diào)函數(shù) ---> Promise ---> Generator ---> async/await.
1.回調(diào)函數(shù): callback
//node讀取文件
fs.readFile(xxx, "utf-8", function(err, data) {
    //code
});

回調(diào)函數(shù)的使用場(chǎng)景(包括但不限于):

事件回調(diào)

Node API

setTimeout/setInterval中的回調(diào)函數(shù)

ajax 請(qǐng)求

回調(diào)函數(shù)的優(yōu)點(diǎn): 簡(jiǎn)單。

回調(diào)函數(shù)的缺點(diǎn):

異步回調(diào)嵌套會(huì)導(dǎo)致代碼難以維護(hù),并且不方便統(tǒng)一處理錯(cuò)誤,不能 try catch 和 回調(diào)地獄(如先讀取A文本內(nèi)容,再根據(jù)A文本內(nèi)容讀取B再根據(jù)B的內(nèi)容讀取C...)。

fs.readFile(A, "utf-8", function(err, data) {
    fs.readFile(B, "utf-8", function(err, data) {
        fs.readFile(C, "utf-8", function(err, data) {
            fs.readFile(D, "utf-8", function(err, data) {
                //....
            });
        });
    });
});
2.Promise

Promise 一定程度上解決了回調(diào)地獄的問(wèn)題,Promise 最早由社區(qū)提出和實(shí)現(xiàn),ES6 將其寫(xiě)進(jìn)了語(yǔ)言標(biāo)準(zhǔn),統(tǒng)一了用法,原生提供了Promise對(duì)象。

那么我們看看Promise是如何解決回調(diào)地獄問(wèn)題的,仍然以上文的readFile 為例(先讀取A文本內(nèi)容,再根據(jù)A文本內(nèi)容讀取B再根據(jù)B的內(nèi)容讀取C)。

function read(url) {
    return new Promise((resolve, reject) => {
        fs.readFile(url, "utf8", (err, data) => {
            if(err) reject(err);
            resolve(data);
        });
    });
}
read(A).then(data => {
    return read(B);
}).then(data => {
    return read(C);
}).then(data => {
    return read(D);
}).catch(reason => {
    console.log(reason);
});
Promise 的優(yōu)點(diǎn):

一旦狀態(tài)改變,就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果

可以將異步操作以同步操作的流程表達(dá)出來(lái),避免了層層嵌套的回調(diào)函數(shù)

缺點(diǎn):

無(wú)法取消 Promise

當(dāng)處于pending狀態(tài)時(shí),無(wú)法得知目前進(jìn)展到哪一個(gè)階段

錯(cuò)誤不能被 try catch

假設(shè)有這樣一個(gè)需求:讀取A,B,C三個(gè)文件內(nèi)容,都讀取成功后,再輸出最終的結(jié)果。在Promise之前,我們一般可以借助發(fā)布訂閱模式去實(shí)現(xiàn):

let pubsub = {
    arry: [],
    emit() {
        this.arry.forEach(fn => fn());
    },
    on(fn) {
        this.arry.push(fn);
    }
}

let data = [];
pubsub.on(() => {
    if(data.length === 3) {
        console.log(data);
    }
});
fs.readFile(A, "utf-8", (err, value) => {
    data.push(value);
    pubsub.emit();
});
fs.readFile(B, "utf-8", (err, value) => {
    data.push(value);
    pubsub.emit();
});
fs.readFile(C, "utf-8", (err, value) => {
    data.push(value);
    pubsub.emit();
});

Promise給我們提供了 Promise.all 的方法,對(duì)于這個(gè)需求,我們可以使用 Promise.all 來(lái)實(shí)現(xiàn)。

/**
 * 將 fs.readFile 包裝成promise接口
 */
function read(url) {
    return new Promise((resolve, reject) => {
        fs.readFile(url, "utf8", (err, data) => {
            if(err) reject(err);
            resolve(data);
        });
    });
}

/**
 * 使用 Promise
 * 
 * 通過(guò) Promise.all 可以實(shí)現(xiàn)多個(gè)異步并行執(zhí)行,同一時(shí)刻獲取最終結(jié)果的問(wèn)題
 */
Promise.all([
    read(A),
    read(B),
    read(C)
]).then(data => {
    console.log(data);
}).catch(err => console.log(err));

可執(zhí)行代碼可戳: https://github.com/YvetteLau/...

3.Generator

Generator 函數(shù)是 ES6 提供的一種異步編程解決方案,整個(gè) Generator 函數(shù)就是一個(gè)封裝的異步任務(wù),或者說(shuō)是異步任務(wù)的容器。異步操作需要暫停的地方,都用 yield 語(yǔ)句注明。

Generator 函數(shù)一般配合 yield 或 Promise 使用。Generator函數(shù)返回的是迭代器。對(duì)生成器和迭代器不了解的同學(xué),請(qǐng)自行補(bǔ)習(xí)下基礎(chǔ)。下面我們看一下 Generator 的簡(jiǎn)單使用:

function* gen() {
    let a = yield 111;
    console.log(a);
    let b = yield 222;
    console.log(b);
    let c = yield 333;
    console.log(c);
    let d = yield 444;
    console.log(d);
}
let t = gen();
//next方法可以帶一個(gè)參數(shù),該參數(shù)就會(huì)被當(dāng)作上一個(gè)yield表達(dá)式的返回值
t.next(1); //第一次調(diào)用next函數(shù)時(shí),傳遞的參數(shù)無(wú)效
t.next(2); //a輸出2;
t.next(3); //b輸出3; 
t.next(4); //c輸出4;
t.next(5); //d輸出5;

為了讓大家更好的理解上面代碼是如何執(zhí)行的,我畫(huà)了一張圖,分別對(duì)應(yīng)每一次的next方法調(diào)用:

仍然以上文的 readFile (先讀取A文本內(nèi)容,再根據(jù)A文本內(nèi)容讀取B再根據(jù)B的內(nèi)容讀取C)為例,使用 Generator + co庫(kù)來(lái)實(shí)現(xiàn):

const fs = require("fs");
const co = require("co");
const bluebird = require("bluebird");
const readFile = bluebird.promisify(fs.readFile);

function* read() {
    yield readFile(A, "utf-8");
    yield readFile(B, "utf-8");
    yield readFile(C, "utf-8");
    //....
}
co(read()).then(data => {
    //code
}).catch(err => {
    //code
});

Generator的缺點(diǎn)大約不用我說(shuō)了,除非是找虐,不然一般不會(huì)直接使用 Generator 來(lái)解決異步的(當(dāng)然也不排除是因?yàn)槲也皇炀?~~~

不使用co庫(kù),如何實(shí)現(xiàn)?能否自己寫(xiě)一個(gè)最簡(jiǎn)的 my_co,有助于理解 async/await 的實(shí)現(xiàn)原理 ?請(qǐng)戳: https://github.com/YvetteLau/...

PS: 如果你還不太了解 Generator/yield,建議閱讀ES6相關(guān)文檔。

4.async/await

ES7中引入了 async/await 概念。async 其實(shí)是一個(gè)語(yǔ)法糖,它的實(shí)現(xiàn)就是將 Generator函數(shù)和自動(dòng)執(zhí)行器(co),包裝在一個(gè)函數(shù)中。

async/await 的優(yōu)點(diǎn)是代碼清晰,不用像 Promise 寫(xiě)很多 then 鏈,就可以處理回調(diào)地獄的問(wèn)題。并且錯(cuò)誤可以被try catch。

仍然以上文的readFile (先讀取A文本內(nèi)容,再根據(jù)A文本內(nèi)容讀取B再根據(jù)B的內(nèi)容讀取C) 為例,使用 async/await 來(lái)實(shí)現(xiàn):

const fs = require("fs");
const bluebird = require("bluebird");
const readFile = bluebird.promisify(fs.readFile);


async function read() {
    await readFile(A, "utf-8");
    await readFile(B, "utf-8");
    await readFile(C, "utf-8");
    //code
}

read().then((data) => {
    //code
}).catch(err => {
    //code
});

使用 async/await 實(shí)現(xiàn)此需求:讀取A,B,C三個(gè)文件內(nèi)容,都讀取成功后,再輸出最終的結(jié)果。

function read(url) {
    return new Promise((resolve, reject) => {
        fs.readFile(url, "utf8", (err, data) => {
            if(err) reject(err);
            resolve(data);
        });
    });
}

async function readAsync() {
    let data = await Promise.all([
        read(A),
        read(B),
        read(C)
    ]);
    return data;
}

readAsync().then(data => {
    console.log(data);
});

所以JS的異步發(fā)展史,可以認(rèn)為是從 callback -> promise -> generator -> async/await。async/await 使得異步代碼看起來(lái)像同步代碼,異步編程發(fā)展的目標(biāo)就是讓異步邏輯的代碼看起來(lái)像同步一樣。

因本人水平有限,文中內(nèi)容未必百分百正確,如有不對(duì)的地方,請(qǐng)給我留言,謝謝。

邀請(qǐng)你加入 Step-By-Step 項(xiàng)目

不積跬步無(wú)以至千里。 我是公眾號(hào)【前端宇宙】作者劉小夕,我將和大家一起一步一個(gè)腳印,向前端專(zhuān)家邁進(jìn)。
Step-By-Step

每個(gè)工作日我會(huì)發(fā)布一個(gè)前端相關(guān)的問(wèn)題(目的是為了切實(shí)掌握相關(guān)的知識(shí)點(diǎn)),歡迎在 Issue 區(qū)留下你的答案。

節(jié)假日不會(huì)發(fā)布任何問(wèn)題,希望大家能夠利用節(jié)假日回顧一周所學(xué)。每周末我會(huì)進(jìn)行一次匯總(整理出最優(yōu)答案),以便大家回顧。

參考文章:

[1] 珠峰架構(gòu)課(墻裂推薦)

[2] 細(xì)說(shuō)JavaScript異步函數(shù)發(fā)展歷程

[3] ES6 Promise

[4] ES6 Generator

[5] ES6 async

[6] JavaScript異步編程

謝謝各位小伙伴愿意花費(fèi)寶貴的時(shí)間閱讀本文,如果本文給了您一點(diǎn)幫助或者是啟發(fā),請(qǐng)不要吝嗇你的贊和Star,您的肯定是我前進(jìn)的最大動(dòng)力。https://github.com/YvetteLau/...

關(guān)注小姐姐的公眾號(hào),加入交流群。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/109732.html

相關(guān)文章

  • 細(xì)說(shuō)JS異步發(fā)展歷程

    摘要:換句話說(shuō),當(dāng)一個(gè)異步過(guò)程調(diào)用發(fā)出后,調(diào)用者不會(huì)立刻得到結(jié)果。參考文章珠峰架構(gòu)課墻裂推薦細(xì)說(shuō)異步函數(shù)發(fā)展歷程異步編程謝謝各位小伙伴愿意花費(fèi)寶貴的時(shí)間閱讀本文,如果本文給了您一點(diǎn)幫助或者是啟發(fā),請(qǐng)不要吝嗇你的贊和,您的肯定是我前進(jìn)的最大動(dòng)力。知其然知其所以然,首先了解三個(gè)概念: 1.什么是同步? 所謂同步,就是在發(fā)出一個(gè)調(diào)用時(shí),在沒(méi)有得到結(jié)果之前,該調(diào)用就不返回。但是一旦調(diào)用返回,就得到返回值了...

    Alfred 評(píng)論0 收藏0
  • JavaScript模塊化開(kāi)發(fā)的演進(jìn)歷程

    摘要:參考精讀模塊化發(fā)展模塊化七日談前端模塊化開(kāi)發(fā)那點(diǎn)歷史本文先發(fā)布于我的個(gè)人博客模塊化開(kāi)發(fā)的演進(jìn)歷程,后續(xù)如有更新,可以查看原文。 Brendan Eich用了10天就創(chuàng)造了JavaScript,因?yàn)楫?dāng)時(shí)的需求定位,導(dǎo)致了在設(shè)計(jì)之初,在語(yǔ)言層就不包含很多高級(jí)語(yǔ)言的特性,其中就包括模塊這個(gè)特性,但是經(jīng)過(guò)了這么多年的發(fā)展,如今對(duì)JavaScript的需求已經(jīng)遠(yuǎn)遠(yuǎn)超出了Brendan Eich的...

    anonymoussf 評(píng)論0 收藏0
  • 馬蹄疾 | 詳解 JavaScript 異步機(jī)制及發(fā)展歷程(萬(wàn)字長(zhǎng)文)

    摘要:本文從入手,系統(tǒng)的回顧的異步機(jī)制及發(fā)展歷程。需要提醒的是,文本沒(méi)有討論的異步機(jī)制。本文是專(zhuān)題系列文章之一,后續(xù)會(huì)有更多專(zhuān)題推出地址持續(xù)更新博客地址文章排版真的很漂亮如果覺(jué)得對(duì)你有幫助,歡迎來(lái)點(diǎn)或者來(lái)我的博客親口告訴我本文從Event Loop、Promise、Generator、async await入手,系統(tǒng)的回顧 JavaScript 的異步機(jī)制及發(fā)展歷程。 需要提醒的是,文本沒(méi)有討論 ...

    KoreyLee 評(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
  • 前端的發(fā)展歷程

    摘要:前端的發(fā)展歷程什么是前端前端針對(duì)瀏覽器的開(kāi)發(fā),代碼在瀏覽器運(yùn)行后端針對(duì)服務(wù)器的開(kāi)發(fā),代碼在服務(wù)器運(yùn)行前端三劍客超文本標(biāo)記語(yǔ)言是構(gòu)成世界的基石。 前端的發(fā)展歷程 什么是前端 前端:針對(duì)瀏覽器的開(kāi)發(fā),代碼在瀏覽器運(yùn)行 后端:針對(duì)服務(wù)器的開(kāi)發(fā),代碼在服務(wù)器運(yùn)行 前端三劍客 HTML CSS JavaScript HTML HTML(超文本標(biāo)記語(yǔ)言——HyperText Markup ...

    劉明 評(píng)論0 收藏0

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

0條評(píng)論

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