前言
在實際編碼中,我們經(jīng)常會遇到Javascript代碼異步執(zhí)行的場景,比如ajax的調(diào)用、定時器的使用等,在這樣的場景下也經(jīng)常會出現(xiàn)這樣那樣匪夷所思的bug或者糟糕的代碼片段,那么處理好你的Javascript異步代碼成為了異步編程至關(guān)重要的前提。下面我們從問題出發(fā),一步步完善你的異步代碼。
異步問題
1. 回調(diào)地獄
首先,我們來看下異步編程中最常見的一種問題,便是回調(diào)地獄。它的出現(xiàn)是由于異步代碼執(zhí)行時間的不確定性及代碼間的依賴關(guān)系引發(fā)的,比如:
// 一個動畫結(jié)束后,執(zhí)行下一個動畫,下一個動畫結(jié)束后再執(zhí)行下一個動畫$('#box').animate({width: '100px'}, 1000, function(){ $('#box').animate({height: '100px'}, 1000, function(){ $('#box').animate({left: 100}, 1000); });});由于我們不知道第一個動畫什么時候開始或者什么時候結(jié)束,所以我們把第二個動畫的執(zhí)行內(nèi)容放到了第一個動畫的結(jié)束事件里,把第三個動畫放到了第二個動畫的結(jié)束事件里,這時候如果有很多這樣的動畫,那么就會形成回調(diào)地獄。
2. 捕獲異常
除了回調(diào)地獄,如果我們需要在異步代碼中捕獲異常也比較麻煩,可能需要手動配置捕獲方法:
try { throw new Error('fail');} catch (e) { console.log(e);}這樣的代碼書寫明顯不是我們想要的,不僅不利于維護,而且也在一定程度上違背了良好的Javascript編碼規(guī)范。
解決方案
那么我們?nèi)绾蝺?yōu)雅的寫好我們的異步代碼呢?我主要列了以下5種常見方案:
1. callback
callback顧名思義便是回調(diào),但并不是將回調(diào)內(nèi)容放在異步方法里,而是放到外部的回調(diào)函數(shù)中,比如問題1的代碼我們通過callback可以變成這樣:
$('#box').animate({width: '100px'}, 1000, autoHeight);function autoHeight() { $('#box').animate({height: '100px'}, 1000, autoLeft);}function autoLeft() { $('#box').animate({left: 100}, 1000);}如此我們看似異步的代碼變成了同步的寫法,避免了層層嵌套的寫法,看上去也流暢了很多。同時使用callback也是異步編程最基礎(chǔ)和核心的一種解決思路。
2. Promise
基于callback,Promise目前也被廣泛運用,其是異步編程的一種解決方案,比傳統(tǒng)的回調(diào)函數(shù)解決方案更合理和強大。相信了解ES6的同學(xué)肯定不會陌生。
比如我們現(xiàn)在有這樣一個場景,我們需要異步加載一張圖片,在圖片加載成功后做一些操作,這里我不想用回調(diào)函數(shù)或者將邏輯寫在圖片的成功事件里,那么用Promise我們可以這樣寫:
let p = new Promise((resolve, reject) => { let img = new Image(); // 創(chuàng)建圖片對象 // 圖片加載成功事件 img.onload = function() { resolve(img); // 輸出圖片對象 }; // 圖片加載失敗事件 img.onerror = function() { reject(new Error('load error')); // 輸出錯誤 }; img.src = 'xxx'; // 圖片路徑});// Promise then回調(diào)p.then(result => { $('#box').append(result); // 成功后我們把圖片放到頁面上}).catch(error => { console.log(error); // 打印錯誤})
新聞熱點
疑難解答
圖片精選