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

資訊專欄INFORMATION COLUMN

JS 異步(callback→Promise→async/await)

gougoujiang / 3159人閱讀

摘要:異步編程三座大山原型原型鏈作用域閉包同步異步。異步操作執(zhí)行完畢后,再執(zhí)行該回調(diào)函數(shù),確保回調(diào)在異步操作之后執(zhí)行?;卣{(diào)函數(shù)本身是我們約定俗成的一種叫法,我們定義它,但是并不會自己去執(zhí)行它,它最終被其他人執(zhí)行了。

JS異步編程

JS三座大山:原型原型鏈、作用域閉包、同步異步。
之前有寫過自己對閉包的理解,今天來總結(jié)一下JS中的異步。

思考(案例來自stackoverflow):

function foo(){
    var result;
    $ajax({
        url:"...",
        success:function(response){
            result=response;
            //return response;//tried this one as well
        }
    });
    return result;
}
var result=foo();

初學(xué)異步的時候,這里是很容易錯的地方,你想要獲取從服務(wù)器端返回的數(shù)據(jù),結(jié)果卻一直undefined。
分析:
JavaScript是單線程語言,但是js中有很多任務(wù)耗時比較長,比如ajax請求,如果都按照順序進(jìn)行,往往會出現(xiàn)瀏覽器無響應(yīng)的情況,所以就需要異步的形式。JS中所有的任務(wù)可以分為兩種:同步任務(wù)和異步任務(wù)。

同步任務(wù):在主線程上排隊執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù);

異步任務(wù):不進(jìn)入主線程,而進(jìn)入任務(wù)隊列中的任務(wù),只有任務(wù)隊列通知主線程,某個異步任務(wù)可以執(zhí)行了,這個任務(wù)才會進(jìn)入主線程執(zhí)行。

事件循環(huán)(Event Loop):只有執(zhí)行棧中的所有同步任務(wù)都執(zhí)行完畢,系統(tǒng)才會讀取任務(wù)隊列,看看里面的異步任務(wù)哪些可以執(zhí)行,然后那些對應(yīng)的異步任務(wù),結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧,開始執(zhí)行。

異步的解決方案:

下面我們嘗試將上面代碼改正一下,幾種方法如下:
1.callback

function foo(callback){//定義函數(shù)的時候?qū)⒘硪粋€函數(shù)(回調(diào)函數(shù))作為參數(shù)傳入定義的函數(shù)中。
    $ajax({
        //...
        success:callback//異步操作執(zhí)行完畢后,再執(zhí)行該回調(diào)函數(shù),確?;卣{(diào)在異步操作之后執(zhí)行。
    });
}
function myCallback(result){
    //...
}
foo(myCallback);

回調(diào)函數(shù)本身是我們約定俗成的一種叫法,我們定義它,但是并不會自己去執(zhí)行它,它最終被其他人執(zhí)行了。

優(yōu)點:比較容易理解;
缺點:1.高耦合,維護(hù)困難,回調(diào)地獄;2.每個任務(wù)只能指定一個回調(diào)函數(shù);3.如果幾個異步操作之間并沒有順序之分,同樣也要等待上一個操作執(zhí)行結(jié)束再進(jìn)行下一個操作。下圖回調(diào)地獄(圖片來自于新浪微博(@ruanyf)):

2.Promise

function ajax(url){
    return new Promise(function(resolve,reject){
        var xhr=new XMLHttpRequest();
        xhr.onload=function(){
            resolve(this.responseText);
        };
        xhr.onerror=reject;
        xhr.open("GET",url);
        xhr.send();
    });
}
ajax("/echo/json")
    .then(function(result){...})
    .then(function(){...})
    .catch(function(){...});

ES6給我們提供了一個原生的構(gòu)造函數(shù)Promise,Promise代表了一個異步操作,可以將異步對象和回調(diào)函數(shù)脫離開來,通過.then方法在這個異步操作上綁定回調(diào)函數(shù),Promise可以讓我們通過鏈?zhǔn)秸{(diào)用的方法去解決回調(diào)嵌套的問題,而且由于promise.all這樣的方法存在,可以讓同時執(zhí)行多個操作變得簡單。

promise對象存在三種狀態(tài):
1)Fulfilled:成功狀態(tài)
2)Rejected:失敗狀態(tài)
3)Pending:既不是成功也不是失敗狀態(tài),可以理解為進(jìn)行中狀態(tài)

promise對象的兩個重要方法:resolve/reject
1)resolve方法可以使Promise對象的狀態(tài)改變?yōu)槌晒?,同時傳遞一個參數(shù)用于后續(xù)成功后的操作。
2)reject方法可以將Promise對象的狀態(tài)改變?yōu)槭。瑫r將錯誤信息傳遞到后續(xù)錯誤處理的操作。

.then可以使用鏈?zhǔn)秸{(diào)用,原因在于:每一次執(zhí)行該方法時總會返回一個Promise對象。
另外,在then的函數(shù)當(dāng)中的返回值,可以作為后續(xù)操作的參數(shù)(例如:.then(return a).then(console.log(a+b)))

那么問題來了,如果上面代碼異步操作拋出錯誤,會怎么樣?會調(diào)用catch方法指定的回調(diào)函數(shù),處理這個錯誤,而且then方法指定的回調(diào)函數(shù),如果運行中拋出錯誤,也會被catch捕獲。Promise對象的錯誤具有“冒泡”性質(zhì),會一直向后傳遞,直到被捕獲為止,也就是說,錯誤總是會被下一個catch語句捕獲。

理解Promise用法的關(guān)鍵點:
1.then方法是Promise實例的方法,即Promise.prototype上的,它的作用是為Promise實例添加狀態(tài)改變時的回調(diào)函數(shù),這個方法的第一個參數(shù)是resolved狀態(tài)的回調(diào)函數(shù),第二個參數(shù)(可選)是rejected狀態(tài)的回調(diào)函數(shù)。
2.鏈?zhǔn)街械牡诙€then開始,它們的resolve中的參數(shù),是前一個then中resolve的return語句的返回值。
3.關(guān)于執(zhí)行順序:Promise在實例化的時候就會執(zhí)行,也就是如果Promise的實例化語句中函數(shù)console.log輸出語句,它會比then中的先執(zhí)行。Promise.all中傳入的Promise對象的數(shù)組(假設(shè)為p1、p2),即使p2的運行速度比p1快,Promise.all方法仍然會按照數(shù)組中的順序?qū)⒔Y(jié)果返回。
理解了上面這些方便寫原生的Promise,利用觀察者模式。后面補(bǔ)充。

Promise的缺點:
1.當(dāng)處于未完成狀態(tài)時,無法確定目前處于哪一階段。
2.如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部的錯誤不會反映到外部。
3.無法取消Promise,一旦新建它就會立即執(zhí)行,無法中途取消。

3.async/await:

很多人說async/await是異步編程的終極解決方案、
JavaScript 的 async/await 實現(xiàn),離不開 Promise。

var superagent=require("superagent")
function delay(){
    return new Promise(function(resolve,reject){
        setTimeout({
            resolve(42);
        },3000);
    })
}
async function getAllBooks(){
    var bookIDs=await superagent.get("/user/books");
    await delay(1000);
    return await superagent.get("/books/ids="JSON.stringify(bookIDs));
}
getAllBooks()
    .then(function(){});

上面的 delay() 沒有申明為 async。實際上,delay() 本身就是返回的 Promise 對象,加不加 async 結(jié)果都一樣。

只要在函數(shù)名之前加上async關(guān)鍵字,就表明這個函數(shù)內(nèi)部有異步操作。這個異步操作返回一個Promise對象,前面用await關(guān)鍵字注明。函數(shù)執(zhí)行的時候,一旦遇到await,就會先執(zhí)行await后面的表達(dá)式中的內(nèi)容(異步),不再執(zhí)行函數(shù)體后面的語句。等到異步操作執(zhí)行完畢后,再自動返回到函數(shù)體內(nèi),繼續(xù)執(zhí)行函數(shù)體后面的語句。

下面這段來自:https://segmentfault.com/a/11...

async:定義異步函數(shù)
1)自動把函數(shù)轉(zhuǎn)換為Promise
2)當(dāng)調(diào)用異步函數(shù)時,函數(shù)返回值會被resolve處理
3)異步函數(shù)內(nèi)部可以使用await

await:暫停異步函數(shù)的執(zhí)行
1)當(dāng)使用在Promise前面時,await等待Promise完成,并返回Promise的結(jié)果
2)await只能和Promise一起使用,不能和callback一起使用
3)await只能用在async函數(shù)中

async/await并不會取代promise,因為async/await底層依然使用promise。

async function getABC(){
    let A = await getValueA(); // getValueA 花費 2 秒
    let B = await getValueB(); // getValueA 花費 4 秒
    let C = await getValueC(); // getValueA 花費 3 秒
    return A*B*C
}

每次遇到?await?關(guān)鍵字時,Promise 都會停下在,一直到運行結(jié)束,所以總共花費是 2+4+3 = 9 秒。await?把異步變成了同步。

async function getABC() {
    // Promise.all() 允許同時執(zhí)行所有的異步函數(shù)
    let results = await Promise.all([ getValueA, getValueB, getValueC ]); 
    return results.reduce((total,value) => total * value);
}

函數(shù)總耗時為 4 秒(getValueB?的耗時)。

Async 的價值在于用寫同步的方式寫異步,1避免了阻塞,2必免寫回調(diào)

async/await詳細(xì)了解,推薦:https://segmentfault.com/a/11...

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

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

相關(guān)文章

  • 現(xiàn)代JS中的流程控制:詳解Callbacks 、Promises 、Async/Await

    摘要:控制臺將顯示回調(diào)地獄通常,回調(diào)只能由一個異步函數(shù)調(diào)用。更多資源使更友好規(guī)范使用異步函數(shù)簡化異步編碼旅程異步編程是一項在中無法避免的挑戰(zhàn)。 JavaScript經(jīng)常聲稱是_異步_。那是什么意思?它如何影響發(fā)展?近年來這種方法有何變化? 請思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數(shù)語言都處理每...

    shadowbook 評論0 收藏0
  • 現(xiàn)代JS中的流程控制:詳解Callbacks 、Promises 、Async/Await

    摘要:控制臺將顯示回調(diào)地獄通常,回調(diào)只能由一個異步函數(shù)調(diào)用。更多資源使更友好規(guī)范使用異步函數(shù)簡化異步編碼旅程異步編程是一項在中無法避免的挑戰(zhàn)。 JavaScript經(jīng)常聲稱是_異步_。那是什么意思?它如何影響發(fā)展?近年來這種方法有何變化? 請思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數(shù)語言都處理每...

    oujie 評論0 收藏0
  • 現(xiàn)代JS中的流程控制:詳解Callbacks 、Promises 、Async/Await

    摘要:控制臺將顯示回調(diào)地獄通常,回調(diào)只能由一個異步函數(shù)調(diào)用。更多資源使更友好規(guī)范使用異步函數(shù)簡化異步編碼旅程異步編程是一項在中無法避免的挑戰(zhàn)。 JavaScript經(jīng)常聲稱是_異步_。那是什么意思?它如何影響發(fā)展?近年來這種方法有何變化? 請思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數(shù)語言都處理每...

    anquan 評論0 收藏0
  • JavaScript工作原理(四):事件循環(huán),異步編程的興起以及5招async/await實踐

    摘要:事件循環(huán)從回調(diào)隊列中獲取并將其推送到調(diào)用堆棧。如何工作請注意,不會自動將您的回調(diào)函數(shù)放到事件循環(huán)隊列中。它設(shè)置了一個計時器,當(dāng)計時器到期時,環(huán)境將您的回調(diào)函數(shù)放入事件循環(huán)中,以便將來的某個事件會將其選中并執(zhí)行它。 我們將通過回顧第一篇文章中單線程編程的缺點,然后在討論如何克服它們來構(gòu)建令人驚嘆的JavaScript UI。在文章結(jié)尾處,我們將分享5個關(guān)于如何使用async / awai...

    piglei 評論0 收藏0
  • JavaScript 工作原理之四-事件循環(huán)及異步編程的出現(xiàn)和 5 種更好的 async/await

    摘要:函數(shù)會在之后的某個時刻觸發(fā)事件定時器。事件循環(huán)中的這樣一次遍歷被稱為一個。執(zhí)行完畢并出棧。當(dāng)定時器過期,宿主環(huán)境會把回調(diào)函數(shù)添加至事件循環(huán)隊列中,然后,在未來的某個取出并執(zhí)行該事件。 原文請查閱這里,略有改動。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第四章。 現(xiàn)在,我們將會通過回顧單線程環(huán)境下編程的弊端及如何克服這些困難以創(chuàng)建令人驚嘆...

    maochunguang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<