這篇文章跟大家分享5個使用 promise 時的常見錯誤,幫大家快速避坑,希望對大家有幫助!
Promise 提供了一種優雅的方法來處理 JS 中的非同步操作。這也是避免「回調地獄」的解決方案。然而,並沒有太多開發人員了解其中的內容。因此,許多人在實踐中往往會犯錯。 【相關推薦:javascript學習教學】
在本文中,介紹一下使用 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 中使用<span style="font-size: 18px;">#try/catch</span>
區塊
通常情況下,我們使用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 时常犯的五个错误。然而,可能还有很多简单的问题需要仔细解决。
如果你还有更多相关的错误,欢迎留言一起讨论。
英文原文地址:https://blog.bitsrc.io/5-common-mistakes-in-using-promises-bfcc4d62657f
作者:Ravidu Perera
更多编程相关知识,请访问:编程入门!!
以上是快速避坑,聊聊5個用promise的常見錯誤!的詳細內容。更多資訊請關注PHP中文網其他相關文章!