作者:Ravidu Perera
譯者:前端小智
來源:medium
有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。
Promise 提供了一種優雅的方法來處理 JS 中的非同步操作。這也是避免“回撥地獄”的解決方案。然而,並沒有多少開發人員瞭解其中的內容。因此,許多人在實踐中往往會犯錯誤。
在本文中,介紹一下使用 promise 時的五個常見錯誤,希望大家能夠避免這些錯誤。
1.避免 Promise 地獄
通常,Promise是用來避免回撥地獄。但濫用它們也會導致 Promise是地獄。
userLogin('user').then(function(user){
getArticle(user).then(function(articles){
showArticle(articles).then(function(){
//Your code goes here...
});
});
});
在上面的例子中,我們對 userLogin
、getararticle
和 showararticle
巢狀了三個promise。這樣複雜性將按程式碼行比例增長,它可能變得不可讀。
為了避免這種情況,我們需要解除程式碼的巢狀,從第一個 then
中返回 getArticle
,然後在第二個 then
中處理它。
userLogin('user')
.then(getArticle)
.then(showArticle)
.then(function(){
//Your code goes here...
});
2. 在 Promise 中使用 try/catch
塊
通常情況下,我們使用 try/catch
塊來處理錯誤。然而,不建議在 Promise
物件中使用try/catch
。
這是因為如果有任何錯誤,Promise物件會在 catch
內自動處理。
ew Promise((resolve, reject) => {
try {
const data = doThis();
// do something
resolve();
} catch (e) {
reject(e);
}
})
.then(data => console.log(data))
.catch(error => console.log(error));
在上面的例子中,我們在Promise 內使用了 try/catch
塊。
但是,Promise本身會在其作用域內捕捉所有的錯誤(甚至是打字錯誤),而不需要 try/catch
塊。它確保在執行過程中丟擲的所有異常都被獲取並轉換為被拒絕的 Promise。
new Promise((resolve, reject) => {
const data = doThis();
// do something
resolve()
})
.then(data => console.log(data))
.catch(error => console.log(error));
注意:在 Promise 塊中使用 .catch()
塊是至關重要的。否則,你的測試案例可能會失敗,而且應用程式在生產階段可能會崩潰。
3. 在 Promise 塊內使用非同步函式
Async/Await
是一種更高階的語法,用於處理同步程式碼中的多個Promise。當我們在一個函式宣告前使用 async
關鍵字時,它會返回一個 Promise,我們可以使用 await
關鍵字來停止程式碼,直到我們正在等待的Promise解決或拒絕。
但是,當你把一個 Async 函式放在一個 Promise 塊裡面時,會有一些副作用。
假設我們想在Promise 塊中做一個非同步操作,所以使用了 async
關鍵字,但,不巧的是我們的程式碼丟擲了一個錯誤。
這樣,即使使用 catch()
塊或在 try/catch
塊內等待你的Promise,我們也不能立即處理這個錯誤。請看下面的例子。
// 此程式碼無法處理錯誤
new Promise(async () => {
throw new Error('message');
}).catch(e => console.log(e.message));
(async () => {
try {
await new Promise(async () => {
throw new Error('message');
});
} catch (e) {
console.log(e.message);
}
})();
當我在Promise塊內遇到 async
函式時,我試圖將 async
邏輯保持在 Promise 塊之外,以保持其同步性。10次中有9次都能成功。
然而,在某些情況下,可能需要一個 async
函式。在這種情況下,也別無選擇,只能用try/catch
塊來手動管理。
new Promise(async (resolve, reject) => {
try {
throw new Error('message');
} catch (error) {
reject(error);
}
}).catch(e => console.log(e.message));
//using async/await
(async () => {
try {
await new Promise(async (resolve, reject) => {
try {
throw new Error('message');
} catch (error) {
reject(error);
}
});
} catch (e) {
console.log(e.message);
}
})();
4.在建立 Promise 後立即執行 Promise 塊
至於下面的程式碼片斷,如果我們把程式碼片斷放在呼叫HTTP請求的地方,它就會被立即執行。
const myPromise = new Promise(resolve => {
// code to make HTTP request
resolve(result);
});
原因是這段程式碼被包裹在一個Promise建構函式中。然而,有些人可能會認為只有在執行myPromise
的then
方法之後才被觸發。
然而,真相併非如此。相反,當一個Promise被建立時,回撥被立即執行。
這意味著在建立 myPromise
之後到達下面一行時,HTTP請求很可能已經在執行,或者至少處於排程狀態。
Promises 總是急於執行過程。
但是,如果希望以後再執行 Promises,應該怎麼做?如果現在不想發出HTTP請求怎麼辦?是否有什麼神奇的機制內建於 Promises 中,使我們能夠做到這一點?
答案就是使用函式。函式是一種耗時的機制。只有當開發者明確地用 ()
來呼叫它們時,它們才會執行。簡單地定義一個函式還不能讓我們得到什麼。所以,讓 Promise 變得懶惰的最有效方法是將其包裹在一個函式中!
const createMyPromise = () => new Promise(resolve => {
// HTTP request
resolve(result);
});
對於HTTP請求,Promise 建構函式和回撥函式只有在函式被執行時才會被呼叫。所以現在我們有一個懶惰的Promise,只有在我們需要的時候才會執行。
5. 不一定使用 Promise.all() 方法
如果你已經工作多年,應該已經知道我在說什麼了。如果有許多彼此不相關的 Promise,我們可以同時處理它們。
Promise 是併發的,但如你一個一個地等待它們,會太費時間,Promise.all()
可以節省很多時間。
記住,Promise.all() 是我們的朋友
const { promisify } = require('util');
const sleep = promisify(setTimeout);
async function f1() {
await sleep(1000);
}
async function f2() {
await sleep(2000);
}
async function f3() {
await sleep(3000);
}
(async () => {
console.time('sequential');
await f1();
await f2();
await f3();
console.timeEnd('sequential');
})();
上述程式碼的執行時間約為 6
秒。但如果我們用 Promise.all()
代替它,將減少執行時間。
(async () => {
console.time('concurrent');
await Promise.all([f1(), f2(), f3()]);
console.timeEnd('concurrent');
})();
總結
在這篇文章中,我們討論了使用 Promise 時常犯的五個錯誤。然而,可能還有很多簡單的問題需要仔細解決。
如果你還有更多相關的錯誤,歡迎留言一起討論。
~完,我是刷碗智,勵志等退休後,要回家擺地攤的人,我們下期見!
程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug。
原文:https://blog.bitsrc.io/5-comm...
交流
文章每週持續更新,可以微信搜尋 【大遷世界 】 第一時間閱讀,回覆 【福利】 有多份前端視訊等著你,本文 GitHub https://github.com/qq449245884/xiaozhi 已經收錄,歡迎Star。