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

資訊專欄INFORMATION COLUMN

ES6—Async與異步編程(11)

chengjianhua / 3171人閱讀

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

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

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

壞處是只要有一個任務耗時很長,后面的任務都必須排隊等著,會拖延整個程序的執(zhí)行。常見的瀏覽器無響應(假死),往往就是因為某一段Javascript代碼長時間運行(比如死循環(huán)),導致整個頁面卡在這個地方,其他任務無法執(zhí)行。

所以異步編程對JavaScript語言太重要。

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

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

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

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

講的通俗點:

朱自清的《背影》中,父親對朱自清說 :“我買幾個橘子去。你就在此地,不要走動。”

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

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

1、異步編程

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

第一步,驗證用戶是否注冊

第二步,沒有注冊,發(fā)送驗證碼

第三步,填寫驗證碼、密碼,檢驗驗證碼是否正確

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

1.1 回調函數(shù)

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

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

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

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

這種層層嵌套被稱為回調地獄。

1.2 Promise方式

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

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

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

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

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

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

大家初中學過電路,這個就像電路的串聯(lián),如果沒學過也沒關系,你肯定知道jquery有鏈式操作,這個就很類似鏈式操作的寫法,比較符合我們的思維邏輯。

1.3 async/await方式

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

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

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

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

2、async用法

2.1 返回 Promise 對象

async函數(shù)返回一個 Promise 對象。

async函數(shù)內部return語句返回的值,會成為then方法回調函數(shù)的參數(shù)。

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

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

2.2 await 命令

正常情況下,await命令后面是一個 Promise 對象,返回該對象的結果。如果不是 Promise 對象,就直接返回對應的值。

/*成功情況*/
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

注意事項:

await命令只能用在async函數(shù)之中,如果用在普通函數(shù),就會報錯。

/* 錯誤處理 */
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,需要進行try…catch代碼塊中

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

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

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

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

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

代碼中的每次 getSize 調用都需要等待上一次調用完成,同樣是一種性能浪費,而且花費的時間也長。同樣的功能,用這樣的方式會更合適:

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

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

4、總結

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

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

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

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

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

希望小伙們在以后的實戰(zhàn)項目中,多多練習,才能掌握async/await的真正精要。

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

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109521.html

相關文章

  • ES6-7

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

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

    摘要:為什么要異步編程我們在寫前端代碼時,經(jīng)常會對做事件處理操作,比如點擊激活焦點失去焦點等再比如我們用請求數(shù)據(jù),使用回調函數(shù)獲取返回值。這些都屬于異步編程。回調有多個狀態(tài),當響應成功和失敗都有不同的回調函數(shù)。 為什么要異步編程 我們在寫前端代碼時,經(jīng)常會對dom做事件處理操作,比如點擊、激活焦點、失去焦點等;再比如我們用ajax請求數(shù)據(jù),使用回調函數(shù)獲取返回值。這些都屬于異步編程。 也許你...

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

    摘要:為什么要異步編程我們在寫前端代碼時,經(jīng)常會對做事件處理操作,比如點擊激活焦點失去焦點等再比如我們用請求數(shù)據(jù),使用回調函數(shù)獲取返回值。這些都屬于異步編程。回調有多個狀態(tài),當響應成功和失敗都有不同的回調函數(shù)。 為什么要異步編程 我們在寫前端代碼時,經(jīng)常會對dom做事件處理操作,比如點擊、激活焦點、失去焦點等;再比如我們用ajax請求數(shù)據(jù),使用回調函數(shù)獲取返回值。這些都屬于異步編程。 也許你...

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

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

    曹金海 評論0 收藏0

發(fā)表評論

0條評論

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