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

資訊專欄INFORMATION COLUMN

ES6—Async與異步編程(11)

chengjianhua / 3222人閱讀

摘要:所以異步編程對(duì)語言太重要。異步編程我們就以用戶注冊(cè)這個(gè)特別常見的場景為例,講講異步編程。這種層層嵌套被稱為回調(diào)地獄。相比回調(diào)函數(shù)而言,代碼可讀性更高,代碼的執(zhí)行順序一目了然。函數(shù)內(nèi)部語句返回的值,會(huì)成為方法回調(diào)函數(shù)的參數(shù)。

單線程是Javascript語言最本質(zhì)的特性之一,Javascript引擎在運(yùn)行js代碼的時(shí)候,同一個(gè)時(shí)間只能執(zhí)行單個(gè)任務(wù)。

這種模式的好處是實(shí)現(xiàn)起來比較簡單,執(zhí)行環(huán)境相對(duì)單純。

壞處是只要有一個(gè)任務(wù)耗時(shí)很長,后面的任務(wù)都必須排隊(duì)等著,會(huì)拖延整個(gè)程序的執(zhí)行。常見的瀏覽器無響應(yīng)(假死),往往就是因?yàn)槟骋欢蜫avascript代碼長時(shí)間運(yùn)行(比如死循環(huán)),導(dǎo)致整個(gè)頁面卡在這個(gè)地方,其他任務(wù)無法執(zhí)行。

所以異步編程對(duì)JavaScript語言太重要。

有些小伙伴可能還不太理解"異步"。

所謂的"異步",就是一個(gè)任務(wù)分成兩段,先執(zhí)行第一段,然后轉(zhuǎn)而執(zhí)行其他任務(wù),等做好了準(zhǔn)備,再回過頭執(zhí)行第二段。

例如,有一個(gè)任務(wù)是讀取文件進(jìn)行處理,任務(wù)的第一段是向操作系統(tǒng)發(fā)出請(qǐng)求,要求讀取文件。然后,程序執(zhí)行其他任務(wù),等到操作系統(tǒng)返回文件,再接著執(zhí)行任務(wù)的第二段(處理文件)。這種不連續(xù)的執(zhí)行,就叫做異步。

相應(yīng)地,連續(xù)的執(zhí)行就叫做同步。由于是連續(xù)執(zhí)行,不能插入其他任務(wù),所以操作系統(tǒng)從硬盤讀取文件的這段時(shí)間,程序只能干等著。

講的通俗點(diǎn):

朱自清的《背影》中,父親對(duì)朱自清說 :“我買幾個(gè)橘子去。你就在此地,不要走動(dòng)?!?/p>

朱自清沒有走動(dòng),等著買完橘子的父親一起吃橘子,就叫同步。

如果朱自清沒有等父親,獨(dú)自走了,那就不能和父親一起吃橘子,就叫異步。

1、異步編程

我們就以用戶注冊(cè)這個(gè)特別常見的場景為例,講講異步編程。

第一步,驗(yàn)證用戶是否注冊(cè)

第二步,沒有注冊(cè),發(fā)送驗(yàn)證碼

第三步,填寫驗(yàn)證碼、密碼,檢驗(yàn)驗(yàn)證碼是否正確

這個(gè)過程是有一定的順序的,你必須保證上一步完成,才能順利進(jìn)行下一步。

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

function testRegister(){}  // 驗(yàn)證用戶是否注冊(cè)
function sendMessage(){}   // 給手機(jī)發(fā)送驗(yàn)證碼x
function testMessage(){}   // 檢驗(yàn)驗(yàn)證碼是否正確

function doRegister(){  //開始注冊(cè)
    testRegister(data){
        if(data===false){ //已注冊(cè)
            
        }else{ //未注冊(cè)
             sendMessage(data){
                 if(data===true){ //發(fā)送驗(yàn)證碼成功
                    testMessage(data){
                        if(data===true){  //驗(yàn)證碼正確
                           
                        }else{  //驗(yàn)證碼不正確
                            
                        }
                    }    
                }
            }
        }
    }
}

代碼中就已經(jīng)有許多問題,比如雜亂的 if 判斷語句 、層層嵌套的函數(shù),造成代碼的可讀性差,難于維護(hù)。

另外,如果在層層回調(diào)函數(shù)中出現(xiàn)異常,調(diào)試起來是非常讓人奔潰的 —— 由于 try-catch 無法捕獲異步的異常,我們只能不斷不斷的寫 debugger 去追蹤,簡直步步驚心。

這種層層嵌套被稱為回調(diào)地獄。

1.2 Promise方式

Promise就是為了解決回調(diào)地獄問題而提出的。它不是新的語法功能,而是一種新的寫法,允許將回調(diào)函數(shù)的嵌套,改成鏈?zhǔn)秸{(diào)用。采用Promise,連續(xù)讀取多個(gè)文件,寫法如下。

let state=1;  //模擬返回結(jié)果
function step1(resolve,reject){
    console.log("1. 驗(yàn)證用戶是否注冊(cè)");
    if(state==1){
        resolve("未注冊(cè)");
    }else{
        reject("已注冊(cè)");
    }
}
function step2(resolve,reject){
    console.log("2.給手機(jī)發(fā)送驗(yàn)證碼");
    if(state==1){
        resolve("發(fā)送成功");
    }else{
        reject("發(fā)送失敗");
    }
}
function step3(resolve,reject){
    console.log("3.檢驗(yàn)驗(yàn)證碼是否正確");
     if(state==1){
        resolve("驗(yàn)證碼正確");
    }else{
        reject("驗(yàn)證碼不正確");
    }
}

new Promise(testRegister).then(function(val){ // 驗(yàn)證用戶是否注冊(cè)
    console.log(val);
    return new Promise(sendMessage);   // 給手機(jī)發(fā)送驗(yàn)證碼
}).then(function(val){
     console.log(val);
    return new Promise(testMessage);  // 檢驗(yàn)驗(yàn)證碼是否正確
}).then(function(val){
    console.log(val);
    return val;
});

回調(diào)函數(shù)采用了嵌套的方式依次調(diào)用testRegister()、sendMessage() 和testMessage(),而Promise使用then將它們鏈接起來。

相比回調(diào)函數(shù)而言,Promise代碼可讀性更高,代碼的執(zhí)行順序一目了然。

Promise的方式雖然解決了回調(diào)地獄,但是最大問題是代碼冗余,原來的任務(wù)被Promise 包裝了一下,不管什么操作,一眼看去都是一堆 then,原來的語義變得很不清楚。代碼流程不能很好的表示執(zhí)行流程。

大家初中學(xué)過電路,這個(gè)就像電路的串聯(lián),如果沒學(xué)過也沒關(guān)系,你肯定知道jquery有鏈?zhǔn)讲僮?,這個(gè)就很類似鏈?zhǔn)讲僮鞯膶懛?,比較符合我們的思維邏輯。

1.3 async/await方式

async語法是對(duì)new Promise的包裝,await語法是對(duì)then方法的提煉。

 async function doRegister(url) {
  let data  = await testRegister();     // 驗(yàn)證用戶是否注冊(cè)
  let data2 = await sendMessage(data);  // 給手機(jī)發(fā)送驗(yàn)證碼
  let data3 = await testMessage(data2); // 檢驗(yàn)驗(yàn)證碼是否正確
  return data3
}

上面的代碼雖然短,但是每一句都極為重要。data 是 await testRegister的返回結(jié)果,data2 又使用了 data 作為sendMessage的參數(shù),data3 又使用了data2 作為testMessage的參數(shù)。

只要在doRegister前面加上關(guān)鍵詞async,在函數(shù)內(nèi)的異步任務(wù)前添加await聲明即可。如果忽略這些額外的關(guān)鍵字,簡直就是完完全全的同步寫法。

2、async用法

2.1 返回 Promise 對(duì)象

async函數(shù)返回一個(gè) Promise 對(duì)象。

async函數(shù)內(nèi)部return語句返回的值,會(huì)成為then方法回調(diào)函數(shù)的參數(shù)。

async function f() {
  return "aaa";
}

f().then(v => console.log(v))
//aaa
//Promise {: undefined}

2.2 await 命令

正常情況下,await命令后面是一個(gè) Promise 對(duì)象,返回該對(duì)象的結(jié)果。如果不是 Promise 對(duì)象,就直接返回對(duì)應(yīng)的值。

/*成功情況*/
async function f() {
  return await 123;
}
f().then(value => console.log(value));  // 123
/*失敗情況*/
async function f() {
  return Promise.reject("error");
}
f().catch(e => console.error(e));   // error

注意事項(xiàng):

await命令只能用在async函數(shù)之中,如果用在普通函數(shù),就會(huì)報(bào)錯(cuò)。

/* 錯(cuò)誤處理 */
function f(db) {
  let docs = [1, 2, 3];
  for(let doc of docs) {
    await db.push(doc);
  }
  return db; // Uncaught SyntaxError: Unexpected identifier
}





/* 正確處理(順序執(zhí)行) */
async function f(db) {
  let docs = [1, 2, 3];
  for(let doc of docs) {
    await db.push(doc);
  }
  return db;
}

2.3 async中異常處理

通過使用 async/await,我們就可以配合 try/catch 來捕獲異步操作過程中的問題,包括 Promise 中reject 的數(shù)據(jù)。

await后面可能存在reject,需要進(jìn)行try…catch代碼塊中

async function f() {
  try {
    await Promise.reject("出錯(cuò)了");
  } catch(e) {
    console.error(e);
  }
  return Promise.resolve("hello");
}
f().then(v => console.log(v));   // 出錯(cuò)了 hello

3、并聯(lián)中的await

async/await 語法確實(shí)很簡單好用,但也容易使用不當(dāng),還要根據(jù)具體的業(yè)務(wù)場景需求來定。

例如我們需要獲取一批圖片的大小信息:

async function allPicInfo (imgs) {
  const result = [];
  for (const img of imgs) {
    result.push(await getSize(img));
  }
}

代碼中的每次 getSize 調(diào)用都需要等待上一次調(diào)用完成,同樣是一種性能浪費(fèi),而且花費(fèi)的時(shí)間也長。同樣的功能,用這樣的方式會(huì)更合適:

async function allPicInfo (imgs) {
  return Promise.all(imgs.map(img => getSize(img)));
}

多個(gè)異步操作,如果沒有繼承關(guān)系,最好同時(shí)觸發(fā)。

4、總結(jié)

從最早的回調(diào)函數(shù),到 Promise 對(duì)象,每次都有所改進(jìn),但又讓人覺得不徹底。它們都有額外的復(fù)雜性,都需要理解抽象的底層運(yùn)行機(jī)制。

例如有三個(gè)請(qǐng)求需要發(fā)生,第三個(gè)請(qǐng)求是依賴于第二個(gè)請(qǐng)求的結(jié)果,第二個(gè)請(qǐng)求依賴于第一個(gè)請(qǐng)求的結(jié)果。若用 ES5實(shí)現(xiàn)會(huì)有3層的回調(diào),導(dǎo)致代碼的橫向發(fā)展。若用Promise 實(shí)現(xiàn)至少需要3個(gè)then,導(dǎo)致代碼的縱向發(fā)展。然而,async/await 解決了這些問題。

從實(shí)現(xiàn)上來看 async/await 是在 生成器、Promise 基礎(chǔ)上構(gòu)建出來的新語法:以生成器實(shí)現(xiàn)流程控制,以 Promise 實(shí)現(xiàn)異步控制。

但是,不要因此小看 async/await,使用同步的方式寫異步代碼其實(shí)非常強(qiáng)大。

async/await 在語義化、簡化代碼、錯(cuò)誤處理等方面有很多的優(yōu)勢(shì),畢竟用async/ wait編寫條件代碼要簡單得多,還可以使用相同的代碼結(jié)構(gòu)(眾所周知的try/catch語句)處理同步和異步錯(cuò)誤,所以常被稱為JavaScript異步編程的終極解決方案,可見其重要性和優(yōu)勢(shì)。

希望小伙們?cè)谝院蟮膶?shí)戰(zhàn)項(xiàng)目中,多多練習(xí),才能掌握async/await的真正精要。

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

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

相關(guān)文章

  • ES6-7

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

    mudiyouyou 評(píng)論0 收藏0
  • 《深入理解ES6》筆記—— Promise異步編程11

    摘要:為什么要異步編程我們?cè)趯懬岸舜a時(shí),經(jīng)常會(huì)對(duì)做事件處理操作,比如點(diǎn)擊激活焦點(diǎn)失去焦點(diǎn)等再比如我們用請(qǐng)求數(shù)據(jù),使用回調(diào)函數(shù)獲取返回值。這些都屬于異步編程。回調(diào)有多個(gè)狀態(tài),當(dāng)響應(yīng)成功和失敗都有不同的回調(diào)函數(shù)。 為什么要異步編程 我們?cè)趯懬岸舜a時(shí),經(jīng)常會(huì)對(duì)dom做事件處理操作,比如點(diǎn)擊、激活焦點(diǎn)、失去焦點(diǎn)等;再比如我們用ajax請(qǐng)求數(shù)據(jù),使用回調(diào)函數(shù)獲取返回值。這些都屬于異步編程。 也許你...

    ssshooter 評(píng)論0 收藏0
  • 《深入理解ES6》筆記—— Promise異步編程11

    摘要:為什么要異步編程我們?cè)趯懬岸舜a時(shí),經(jīng)常會(huì)對(duì)做事件處理操作,比如點(diǎn)擊激活焦點(diǎn)失去焦點(diǎn)等再比如我們用請(qǐng)求數(shù)據(jù),使用回調(diào)函數(shù)獲取返回值。這些都屬于異步編程。回調(diào)有多個(gè)狀態(tài),當(dāng)響應(yīng)成功和失敗都有不同的回調(diào)函數(shù)。 為什么要異步編程 我們?cè)趯懬岸舜a時(shí),經(jīng)常會(huì)對(duì)dom做事件處理操作,比如點(diǎn)擊、激活焦點(diǎn)、失去焦點(diǎn)等;再比如我們用ajax請(qǐng)求數(shù)據(jù),使用回調(diào)函數(shù)獲取返回值。這些都屬于異步編程。 也許你...

    YacaToy 評(píng)論0 收藏0
  • ECMAScript6(16):異步編程

    摘要:異步編程程序執(zhí)行分為同步和異步,如果程序每執(zhí)行一步都需要等待上一步完成才能開始,此所謂同步。因此異步編程十分重要。 異步編程 程序執(zhí)行分為同步和異步,如果程序每執(zhí)行一步都需要等待上一步完成才能開始,此所謂同步。如果程序在執(zhí)行一段代碼的同時(shí)可以去執(zhí)行另一段代碼,等到這段代碼執(zhí)行完畢再吧結(jié)果交給另一段代碼,此所謂異步。比如我們需要請(qǐng)求一個(gè)網(wǎng)絡(luò)資源,由于網(wǎng)速比較慢,同步編程就意味著用戶必須等...

    曹金海 評(píng)論0 收藏0

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

0條評(píng)論

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