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

資訊專欄INFORMATION COLUMN

夯實基礎(chǔ)-JavaScript異步編程

shadowbook / 955人閱讀

摘要:調(diào)用棧被清空,消息隊列中并無任務(wù),線程停止,事件循環(huán)結(jié)束。不確定的時間點請求返回,將設(shè)定好的回調(diào)函數(shù)放入消息隊列。調(diào)用棧執(zhí)行完畢執(zhí)行消息隊列任務(wù)。請求并發(fā)回調(diào)函數(shù)執(zhí)行順序無法確定。

異步編程

JavaScript中異步編程問題可以說是基礎(chǔ)中的重點,也是比較難理解的地方。首先要弄懂的是什么叫異步?

我們的代碼在執(zhí)行的時候是從上到下按順序執(zhí)行,一段代碼執(zhí)行了之后才會執(zhí)行下一段代碼,這種方式叫同步(synchronous)執(zhí)行,也是我們最容易理解的方式。但是在某些場景下:

網(wǎng)絡(luò)請求:常見的ajax

IO操作:比如readFile

定時器:setTimeout

上面這些場景可能非常耗時,而且時間不定長,這時候這些代碼就不應(yīng)該同步執(zhí)行了,先執(zhí)行可以執(zhí)行的代碼,在未來的某個時間再來執(zhí)行他們的handler,這就是異步。

通過這篇文章我們來了解幾個知識點:

進程線程區(qū)別

消息隊列與事件循環(huán)

JavaScript處理異步的幾種方法

generator與async/await的關(guān)系

基礎(chǔ)知識

先做些準(zhǔn)備工作,補一補一些非常重要的前置的概念。

進程與線程

一個程序(program)至少包含一個進程(process),一個進程至少包含一個線程(thread)。

進程有以下特點:

一個進程可以包含一個或多個線程。

進程在執(zhí)行過程中擁有獨立的內(nèi)存單元。

一個進程可以創(chuàng)建和撤銷另一個進程,這個進程是父進程,被創(chuàng)建的進程稱為子進程。

線程有以下特點:

線程不能獨立運行,必須依賴進程空間。

線程自己基本上不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源(如程序計數(shù)器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。

一個線程可以創(chuàng)建和撤銷另一個線程;同一個進程中的多個線程之間可以并發(fā)執(zhí)行。

從邏輯角度來看,多線程的意義在于一個應(yīng)用程序中,有多個執(zhí)行部分可以同時執(zhí)行。但操作系統(tǒng)并沒有將多個線程看做多個獨立的應(yīng)用,來實現(xiàn)進程的調(diào)度和管理以及資源分配。這就是進程和線程的重要區(qū)別。

畫張圖來簡單描述下:

所有的程序都要交給CPU實現(xiàn)計算任務(wù),但是CPU一個時間點只能處理一個任務(wù)。這時如果多個程序在運行,就涉及到了《操作系統(tǒng)原理》中重要的線程調(diào)度算法,線程是CPU輪轉(zhuǎn)的最小單位,其他上下文信息用所在進程中的。

進程是資源的分配單位,線程是CPU在進程內(nèi)切換的單位。
JavaScript單線程

瀏覽器內(nèi)核是多線程,在內(nèi)核控制下各線程相互配合以保持同步,一個瀏覽器通常由以下常駐線程組成:

GUI 渲染線程

JavaScript引擎線程

定時觸發(fā)器線程

事件觸發(fā)線程

異步http請求線程

Javascript是單線程的,那么為什么Javascript要是單線程的?

這是因為Javascript這門腳本語言誕生的使命所致:JavaScript為處理頁面中用戶的交互,以及操作DOM樹、CSS樣式樹來給用戶呈現(xiàn)一份動態(tài)而豐富的交互體驗和服務(wù)器邏輯的交互處理。如果JavaScript是多線程的方式來操作這些UI DOM,則可能出現(xiàn)UI操作的沖突; 如果Javascript是多線程的話,在多線程的交互下,處于UI中的DOM節(jié)點就可能成為一個臨界資源,假設(shè)存在兩個線程同時操作一個DOM,一個負(fù)責(zé)修改一個負(fù)責(zé)刪除,那么這個時候就需要瀏覽器來裁決如何生效哪個線程的執(zhí)行結(jié)果。當(dāng)然我們可以通過鎖來解決上面的問題。但為了避免因為引入了鎖而帶來更大的復(fù)雜性,Javascript在最初就選擇了單線程執(zhí)行。
阻塞和非阻塞

這時候再理解阻塞非阻塞就好理解了,對于異步任務(wù),單線程的JavaScript如果什么也不干等待異步任務(wù)結(jié)束,這種狀態(tài)就是阻塞的;如果將異步消息放到一邊,過會再處理,就是非阻塞的。

請求不能立即得到應(yīng)答,需要等待,那就是阻塞;否則可以理解為非阻塞。

生活中這種場景太常見了,上廁所排隊就是阻塞,沒人直接上就是非阻塞。

事件循環(huán)(event-loop)

因為JavaScript是單線程的,每個時刻都只能一個事件,所以JavaScript中的同步和異步事件就有了一個奇妙的執(zhí)行順序。

JavaScript在運行時(runtime)會產(chǎn)生一個函數(shù)調(diào)用棧,先入棧的函數(shù)先被執(zhí)行。但是有一些任務(wù)是不需要進入調(diào)用棧的,這些任務(wù)被加入到消息隊列中。當(dāng)函數(shù)調(diào)用棧被清空時候,就會執(zhí)行消息隊列中的任務(wù)(任務(wù)總會關(guān)聯(lián)一個函數(shù),并加入到調(diào)用棧),依次執(zhí)行直至所有任務(wù)被清空。由于JavaScript是事件驅(qū)動,當(dāng)用戶觸發(fā)事件JavaScript再次運行直至清空所有任務(wù),這就是事件循環(huán)。

函數(shù)調(diào)用棧中的任務(wù)永遠優(yōu)先執(zhí)行,調(diào)用棧無任務(wù)時候,遍歷消息隊列中的任務(wù)。消息隊列中的任務(wù)關(guān)聯(lián)的函數(shù)(一般就是callback)放入調(diào)用棧中執(zhí)行。

舉兩個例子:異步請求

function ajax (url, callback){
    var req = new XMLHttpRequest();

    req.onloadend = callback;
    req.open("GET", url, true);
    req.send();
};

console.log(1);
ajax("/api/xxxx", function(res){
    console.log(res);
});
console.log(2);

一個開發(fā)經(jīng)常遇到的業(yè)務(wù)場景,異步請求一個數(shù)據(jù),上述過程用圖表示:

圖中三條線分別表示函數(shù)執(zhí)行的調(diào)用棧,異步消息隊列,以及請求所依賴的網(wǎng)絡(luò)請求線程(瀏覽器自帶)。執(zhí)行順序:

調(diào)用棧執(zhí)行console.log(1);。

調(diào)用棧執(zhí)行ajax方法,方法里面配置XMLHttpRequest的回調(diào)函數(shù),并交由線程執(zhí)行異步請求。

調(diào)用棧繼續(xù)執(zhí)行console.log(2);。

調(diào)用棧被清空,消息隊列中并無任務(wù),JavaScript線程停止,事件循環(huán)結(jié)束。

不確定的時間點請求返回,將設(shè)定好的回調(diào)函數(shù)放入消息隊列。

事件循環(huán)再次啟動,調(diào)用棧中無函數(shù),執(zhí)行消息隊列中的任務(wù)function(res){console.log(res);}。

定時器任務(wù):

console.log(1);
setTimeout(function(){
    console.log(2);
}, 100);
setTimeout(function(){
    console.log(3);
}, 10);
console.log(4);

// 1
// 4
// 3
// 2

跟上面的例子很像,只不過異步請求變成了定時器,上述代碼的指向過程圖:

執(zhí)行順序如下:

調(diào)用棧執(zhí)行console.log(1);。

執(zhí)行setTimeout向消息隊列添加一個定時器任務(wù)1。

執(zhí)行setTimeout向消息隊列添加一個定時器任務(wù)2。

調(diào)用棧執(zhí)行console.log(4);。

調(diào)用棧執(zhí)行完畢執(zhí)行消息隊列任務(wù)1。

調(diào)用棧執(zhí)行完畢執(zhí)行消息隊列任務(wù)2。

消息隊列任務(wù)2執(zhí)行完畢調(diào)用回調(diào)函數(shù)console.log(3);。

消息隊列任務(wù)1執(zhí)行完畢調(diào)用回調(diào)函數(shù)console.log(2);

通過上面例子可以很好理解,就像工作中你正在做一件事情,這時候領(lǐng)導(dǎo)給你安排一個不著急的任務(wù),你停下來跟領(lǐng)導(dǎo)說"等我忙完手里的活就去干",然后把手里的活干完去干領(lǐng)導(dǎo)安排的任務(wù)。所有任務(wù)完成相當(dāng)于完成了一個事件循環(huán)。

macrotasks 和 microtasks

macrotask 和 microtask 都是屬于上述的異步任務(wù)中的一種,分別是一下 API :

macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering

microtasks: process.nextTick(node), Promises, Object.observe(廢棄), MutationObserver

setTimeout 的 macrotask ,和 Promise 的 microtask 有什么不同呢:

console.log("script start");
setTimeout(function() {
  console.log("setTimeout");
}, 0);
Promise.resolve().then(function() {
  console.log("promise1");
}).then(function() {
  console.log("promise2");
});
console.log("script end");

// "script start"
// "script end"
// "promise1"
// "promise2"
// "setTimeout"

這里的運行結(jié)果是Promise的立即返回的異步任務(wù)會優(yōu)先于setTimeout延時為0的任務(wù)執(zhí)行。

原因是任務(wù)隊列分為 macrotasks 和 microtasks,而Promise中的then方法的函數(shù)會被推入 microtasks 隊列,而setTimeout的任務(wù)會被推入 macrotasks 隊列。在每一次事件循環(huán)中,macrotask 只會提取一個執(zhí)行,而 microtask 會一直提取,直到 microtasks 隊列清空

所以上面實現(xiàn)循環(huán)的順序:

執(zhí)行函數(shù)調(diào)用棧中的任務(wù)。

函數(shù)調(diào)用棧清空之后,執(zhí)行microtasks隊列任務(wù)至清空。

執(zhí)行microtask隊列任務(wù)至清空。

并發(fā)(Concurrency)

并發(fā)我們應(yīng)該經(jīng)常聽過,跟他類似的一個詞叫并行。

并發(fā):多個進程在一臺處理機上同時運行,一個時間段內(nèi)處理多件事情,宏觀上好比一個人邊唱邊跳,微觀上這個人唱一句跳一步。(可以類比時間片輪轉(zhuǎn)法,多個線程同時占用一個CPU,外部看來可以并發(fā)處理多個線程)

并行:多態(tài)擁有相同處理能力的處理機在同時處理不同的任務(wù),好比廣場上多個大媽同時再調(diào)廣場舞。(多個CPU同時處理多個線程任務(wù))

在JavaScript中,因為其是單線程的原因,所以決定了其每時刻只能干一件事情,事件循環(huán)是并發(fā)在JavaScript單線程中的一種處理方式。

但是在日常開發(fā)中我們肯定見過,同時發(fā)送多個請求。這種情況下多個網(wǎng)絡(luò)線程和js線程共同占用一個CPU,就是并發(fā)。

異步解決方法

雖然已經(jīng)理解了JavaScript中運行異步任務(wù)的過程,但是這樣顯然對開發(fā)不友好,因為我們通常并不知道異步任務(wù)在何時結(jié)束。所以前人開發(fā)了多種處理異步的方法。每種方法我們都從三個角度考慮其優(yōu)缺點:

單個異步寫法是否簡便。

多個異步按順序執(zhí)行。

多個異步并發(fā)執(zhí)行。

回調(diào)函數(shù) (callback)

一種最常見的處理異步問題的方法,將異步任務(wù)結(jié)束時候要干的事情(回調(diào)函數(shù))作為參數(shù)傳給他,等任務(wù)結(jié)束時候運行回調(diào)函數(shù)。我們常用的$.ajax()setTimeout都屬于這種方式,但是這樣的問題很明顯:多個異步任務(wù)按順序執(zhí)行非??植馈?/p>

// 著名的回調(diào)金字塔
asyncEvent1(()=>{
    asyncEvent2(()=>{
        asyncEvent3(()=>{
            asyncEvent4(()=>{
                ....
            });    
        });
    });
});

上面這種情況非常難以維護,在早期Node項目中經(jīng)常出現(xiàn)這種情況,有人對上面小改動:

function asyncEvent1CB (){
    asyncEvent2(asyncEvent2CB);
}

function asyncEvent2CB (){
    asyncEvent3(asyncEvent3CB);
}

function asyncEvent3CB (){
    asyncEvent4(asyncEvent4CB);
}

function asyncEvent4CB () {
    // ...
}

asyncEvent1(asyncEvent1CB);

這樣講回調(diào)函數(shù)分離出來,邏輯清晰了一些,但是還是很明顯:方法調(diào)用順序是硬編碼,耦合性還是很高。而且一旦同時發(fā)送多個請求,這多個請求的回調(diào)函數(shù)執(zhí)行順序很難保證,維護起來非常麻煩。

這就是回調(diào)函數(shù)的弊端

雖然簡單,但是不利于閱讀維護。

多層回調(diào)順序執(zhí)行耦合性很高。

請求并發(fā)回調(diào)函數(shù)執(zhí)行順序無法確定。

每次只能指定一個回調(diào)函數(shù),出現(xiàn)錯誤程序中斷易崩潰。

雖然回調(diào)函數(shù)這種方式問題很多,但是不可否認(rèn)的是在ES6之前,他就是處理異步問題普遍較好的方式,而且后面很多方式仍然基于回調(diào)函數(shù)。

事件監(jiān)聽(litenter)

JavaScript是事件驅(qū)動,任務(wù)的執(zhí)行不取決代碼的順序,而取決于某一個事件是否發(fā)生。DOM中有大量事件如onclick,onload,onerror等等。

$(".element1").on("click", function(){
    console.log(1);
});

$("#element2").on("click", function(){
    console.log(2);
});

document.getElementById("#element3").addEventListener("click", function(){
    console.log(3);
}, false);

例如上面這段代碼 你無法預(yù)知輸出結(jié)果,因為事件觸發(fā)無法被預(yù)知。跟這個很像的還有訂閱者發(fā)布者模式:

github上有個有意思的小demo。注冊在發(fā)布者里面的回調(diào)函數(shù)何時被觸發(fā)取決于發(fā)布者何時發(fā)布事件,這個很多時候也是不可預(yù)知的。

回調(diào)函數(shù)與事件監(jiān)聽的區(qū)別:

回調(diào)函數(shù)多是一對一的關(guān)系,事件監(jiān)聽可以是多對一。

運行異步函數(shù),在一個不確定的時間段之后運行回調(diào)函數(shù);不確定何時觸發(fā)事件,但是觸發(fā)事件同步響應(yīng)事件的回調(diào)。

事件監(jiān)聽相對于回調(diào)函數(shù),可配置的監(jiān)聽(可增可減)關(guān)系減少了耦合性。

不過事件監(jiān)聽也存在問題:

多對多的監(jiān)聽組成了一個復(fù)雜的事件網(wǎng)絡(luò),單個節(jié)點通常監(jiān)聽了多個事件,維護成本很大。

多個異步事件仍然還是回調(diào)的形式。

Promise

promise出場了,當(dāng)年理解promise花了我不少功夫。Promise確實跟前兩者很不一樣,簡單說下promise。

Promise中文可以翻譯成承諾,現(xiàn)在與未來的一種關(guān)系,我承諾我會調(diào)用你的函數(shù)。

Promise三種狀態(tài):pending(進行中),fulfilled(已成功),rejected(已失?。錉顟B(tài)只能從進行中到成功或者是失敗,不可逆。

已成功和已失敗可以承接不同的回調(diào)函數(shù)。

支持.then鏈?zhǔn)秸{(diào)用,將異步的寫法改成同步。

原生支持了race, all等方法,方便適用常見開發(fā)場景。

promise更詳細的內(nèi)容可以看阮一峰老師的文章。

Promise對于異步處理已經(jīng)十分友好,大多生產(chǎn)環(huán)境已經(jīng)在使用,不過仍有些缺點:

Promise一旦運行,不能終止掉。

利用Promise處理一個異步的后續(xù)處理十分簡便,但是處理多個請求按順序執(zhí)行仍然很不方便。

Generator

中文翻譯成"生成器",ES6中提供的一種異步編程解決方案,語法行為與傳統(tǒng)函數(shù)完全不同。簡單來說,我可以聲明一個生成器,生成器可以在執(zhí)行的時候暫停,交出函數(shù)執(zhí)行權(quán)給其他函數(shù),然后其他函數(shù)可以在需要的時候讓該函數(shù)再次運行。這與之前的JavaScript聽起來完全不同。

詳細的內(nèi)容參考阮一峰老師的文章,這里我們來據(jù)幾個例子,正常的ajax調(diào)用寫法看起來如下:

// 使用setTimeout模擬異步
function ajax (url, cb){
    setTimeout(function(){
        cb("result");
    }, 100);
}

ajax("/api/a", function(result){
    console.log(result);
});

// "result"

一旦我們想要多個異步按順序執(zhí)行,簡直是噩夢。這里使用generator處理異步函數(shù)利用了一個特點:調(diào)用next()函數(shù)就會繼續(xù)執(zhí)行下去,所以利用這個特點我們處理異步原理:

將異步邏輯封裝成一個生成器。

將生成器的異步部分yield出去。

在異步的回調(diào)部分調(diào)用next()將生成器繼續(xù)進行下去。

這樣同步,異步,回調(diào)分離,處理異步寫起來非常簡便。

我們對上面的例子加以改進:

// 使用setTimeout模擬異步
function ajax (url, cb){
    setTimeout(function(){
        cb(url + " result.");
    }, 100);
}

function ajaxCallback(result){
    console.log(result);
    it.next(result);
}

function* ajaxGen (){
    var aResult = yield ajax("/api/a", ajaxCallback); 
    console.log("aResult: " + aResult);
    var bResult = yield ajax("/api/b", ajaxCallback); 
    console.log("bResult: " + bResult);
}

var it = ajaxGen();
it.next();

// /api/a result.
// aResult: /api/a result.
// /api/b result.
// bResult: /api/b result.

運行下上面代碼,可以看到控制臺輸出結(jié)果居然跟我們書寫的順序一樣!我們稍加改動:

// 使用setTimeout模擬異步
function ajax (url, cb){
    setTimeout(function(){
        cb(url + " result.");
    }, 100);
}

function run (generator) {
    var it = generator(ajaxCallback);
    
    function ajaxCallback(result){
        console.log(result);
        it.next(result);
    }
    
    it.next();
};

run(function* (cb){
    var aResult = yield ajax("/api/a", cb); 
    console.log("aResult: " + aResult);
    var bResult = yield ajax("/api/b", cb); 
    console.log("bResult: " + bResult);
});

簡單幾下改造便可以生成一個自執(zhí)行的生成器函數(shù),同時也完成了異步場景同步化寫法。generator的核心在于:同步,異步,回調(diào)三者分離,遇到異步交出函數(shù)執(zhí)行權(quán),再利用回調(diào)控制程序生成器繼續(xù)進行。上面的run函數(shù)只是一個簡單的實現(xiàn),業(yè)界已經(jīng)有CO這樣成熟的工具。實際上開發(fā)過程中通常使用generator搭配Promise實現(xiàn),再來修改上面的例子:

// 使用setTimeout模擬異步
function ajax (url){
    return new Promise(function(resolve, reject){
        setTimeout(function(){
            resolve(url + " result.");
        }, 100);
    });
}

function run (generator) {
    var it = generator();
    
    function next(result){
        var result = it.next(result);
        if (result.done) return result.value;
        result.value.then(function(data){
            console.log(data);
              next(data);
        });
    }
    
    next();
};

run(function* (){
    var aResult = yield ajax("/api/a"); 
    console.log("aResult: " + aResult);
    var bResult = yield ajax("/api/b"); 
    console.log("bResult: " + bResult);
});

使用Promise來代替callback,理解上花費點時間,大大提高了效率。上面是一種常見,之前我用過generator實現(xiàn)多張圖片并發(fā)上傳,這種情況下利用generator控制上傳上傳數(shù)量,達到斷斷續(xù)續(xù)上傳的效果。

進化到generator這一步可以說是相當(dāng)智能了,無論是單個異步,多個按順序異步,并發(fā)異步處理都十分友好,但是也有幾個問題:

ES6瀏覽器支持問題,需要polyfill和babel的支持。

需要借助CO這樣的工具來完成,流程上理解起來需要一定時間。

有沒有更簡便的方法?

async/await

理解了上面的generator,再來理解async/await就簡單多了。

ES2017 標(biāo)準(zhǔn)引入了 async 函數(shù),使得異步操作變得更加方便。async 函數(shù)是什么?一句話,它就是 Generator 函數(shù)的語法糖。

再看一遍上面的例子,然后修改上面的例子用async/await:

// 使用setTimeout模擬異步
function ajax (url){
    return new Promise(function(resolve, reject){
        setTimeout(function(){
            console.log(url + " result.");
            resolve(url + " result.");
        }, 100);
    });
}

async function ajaxAsync () {
    var aResult = await ajax("/api/a"); 
    console.log("aResult: " + aResult);
    var bResult = await ajax("/api/b"); 
    console.log("bResult: " + bResult);
}

ajaxAsync();

可以明顯的看到,async/await寫法跟generator最后一個例子很像,基本上就是使用async/await關(guān)鍵字封裝了一個自執(zhí)行的run方法。

async函數(shù)對 Generator 函數(shù)的改進,體現(xiàn)在以下四點。

內(nèi)置執(zhí)行器:Generator 函數(shù)的執(zhí)行必須靠執(zhí)行器,所以才有了co模塊,而async函數(shù)自帶執(zhí)行器。也就是說,async函數(shù)的執(zhí)行,與普通函數(shù)一模一樣,只要一行。

更好的語義:async和await,比起星號和yield,語義更清楚了。async表示函數(shù)里有異步操作,await表示緊跟在后面的表達式需要等待結(jié)果。

更廣的適用性:co模塊約定,yield命令后面只能是 Thunk 函數(shù)或 Promise 對象,而async函數(shù)的await命令后面,可以是 Promise 對象和原始類型的值(數(shù)值、字符串和布爾值,但這時等同于同步操作)。

返回值是 Promise:async函數(shù)的返回值是 Promise 對象,這比 Generator 函數(shù)的返回值是 Iterator 對象方便多了。你可以用then方法指定下一步的操作。

這里async/await不做深入介紹,詳情移步阮一峰老師的博客。

Web worker

一個很不常用的api,但是是一個異步編程的方法,跟以上幾種又不太一樣。

你可能會遇到一個非常耗時的計算任務(wù),如果在js線程里運行會造成頁面卡頓,這時使用web worker,將計算任務(wù)丟到里面去,等計算完成再以事件監(jiān)聽的方式通知主線程處理,這是一個web work的應(yīng)用場景。在這時候,瀏覽器中是有多個線程在處理js的,worker同時可以在創(chuàng)建子線程,實現(xiàn)js"多線程"。web worker的文檔。實戰(zhàn)的話看這篇。

與前面幾種方法不同的是,我們絞盡腦汁想把異步事件同步化,但是web worker卻反其道而行,將同步的代碼放到異步的線程中。

目前,web worker通常用于頁面優(yōu)化的一種手段,使用場景:

使用專用線程進行數(shù)學(xué)運算:Web Worker最簡單的應(yīng)用就是用來做后臺計算,而這種計算并不會中斷前臺用戶的操作。

圖像處理:通過使用從或者元素中獲取的數(shù)據(jù),可以把圖像分割成幾個不同的區(qū)域并且把它們推送給并行的不同Workers來做計算。

大量數(shù)據(jù)的檢索:當(dāng)需要在調(diào)用 ajax后處理大量的數(shù)據(jù),如果處理這些數(shù)據(jù)所需的時間長短非常重要,可以在Web Worker中來做這些,避免凍結(jié)UI線程。

背景數(shù)據(jù)分析:由于在使用Web Worker的時候,我們有更多潛在的CPU可用時間,我們現(xiàn)在可以考慮一下JavaScript中的新應(yīng)用場景。例如,我們可以想像在不影響UI體驗的情況下實時處理用戶輸入。利用這樣一種可能,我們可以想像一個像Word(Office Web Apps 套裝)一樣的應(yīng)用:當(dāng)用戶打字時后臺在詞典中進行查找,幫助用戶自動糾錯等等。

總結(jié)

JavaScript中的異步編程方式目前來說大致這些,其中回調(diào)函數(shù)這種方式是最簡單最常見的,Promise是目前最受歡迎的方式。前四種方式讓異步編碼模式使我們能夠編寫更高效的代碼,而最后一種web worker則讓性能更優(yōu)。這里主要是對異步編程流程梳理,前提知識點的補充,而對于真正的異步編程方式則是以思考分析為主,使用沒有過多介紹。最后補充一個連接:JavaScript異步編程常見面試題,幫助理解。

參考

《你所不知道JavaScript》

《JavaScript高級程序設(shè)計》

瀏覽器進程?線程?傻傻分不清楚!

線程和進程的區(qū)別是什么?

并發(fā)模型與事件循環(huán)

理解 JavaScript 中的 macrotask 和 microtask

【轉(zhuǎn)向Javascript系列】深入理解Web Worker

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

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

相關(guān)文章

  • 夯實基礎(chǔ)-作用域與閉包

    摘要:作用域分類作用域共有兩種主要的工作模型。換句話說,作用域鏈?zhǔn)腔谡{(diào)用棧的,而不是代碼中的作用域嵌套。詞法作用域詞法作用域中,又可分為全局作用域,函數(shù)作用域和塊級作用域。 一篇鞏固基礎(chǔ)的文章,也可能是一系列的文章,梳理知識的遺漏點,同時也探究很多理所當(dāng)然的事情背后的原理。 為什么探究基礎(chǔ)?因為你不去面試你就不知道基礎(chǔ)有多重要,或者是說當(dāng)你的工作經(jīng)歷沒有亮點的時候,基礎(chǔ)就是檢驗?zāi)愫脡牡囊豁?..

    daydream 評論0 收藏0
  • 夯實JS基礎(chǔ)(一):this的指向問題和經(jīng)典面試題

    摘要:很多高級編程語言都給新創(chuàng)建的對象分配一個引用自身的指針比如中的指針,中的,也有指針,雖然它的指向可能相對復(fù)雜些,但是指向的,永遠只可能是對象。 很多高級編程語言都給新創(chuàng)建的對象分配一個引用自身的指針,比如JAVA、C++中的this指針,python中的self,JavaScript也有this指針,雖然它的指向可能相對復(fù)雜些,但是this指向的,永遠只可能是對象。 一、在一般函數(shù)方法...

    EasonTyler 評論0 收藏0
  • 夯實JS基礎(chǔ)(一):this的指向問題和經(jīng)典面試題

    摘要:很多高級編程語言都給新創(chuàng)建的對象分配一個引用自身的指針比如中的指針,中的,也有指針,雖然它的指向可能相對復(fù)雜些,但是指向的,永遠只可能是對象。 很多高級編程語言都給新創(chuàng)建的對象分配一個引用自身的指針,比如JAVA、C++中的this指針,python中的self,JavaScript也有this指針,雖然它的指向可能相對復(fù)雜些,但是this指向的,永遠只可能是對象。 一、在一般函數(shù)方法...

    lucas 評論0 收藏0
  • 程序員入門學(xué)習(xí)指南

    摘要:程序員的入門規(guī)劃我該學(xué)習(xí)什么語言這個問題困擾了幾乎所有的程序員,比如應(yīng)用廣好就業(yè),比如入門簡單,和安卓待遇高,和開發(fā)效率高,是萬能語言,和前端缺人才等等個人見解先學(xué)習(xí)難度小,大眾化的編程語言,比如,,,這幾個學(xué)哪一種其實差不多,入門以后看自 程序員的入門規(guī)劃 1.我該學(xué)習(xí)什么語言? 這個問題困擾了幾乎所有的程序員,比如java應(yīng)用廣好就業(yè),比如php入門簡單,ios和安卓待遇高,rub...

    Kahn 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<