JavaScript >> Javascript 文檔 >  >> Node.js

Node.js 中的承諾

簡介

JavaScript 是單線程 ,這意味著包括事件在內的所有內容都在同一個線程上運行。如果線程不是空閒的,代碼執行會延遲到空閒為止。這可能是我們應用程序的瓶頸,因為它確實會導致嚴重的性能問題。

我們可以通過不同的方法來克服這個限制。在本文中,我們將探討在 JavaScript 中處理異步任務的現代方式 - Promise s.

回調和回調地獄

如果您是 JavaScript 開發人員,您可能聽說過(如果不使用)回調

function hello() {
    console.log('Hello World!');
}

setTimeout(hello, 5000);

這段代碼執行一個函數,setTimeout() ,等待定義的時間(以毫秒為單位),作為第二個參數傳遞給它,5000 .時間過去後,才執行函數hello ,作為第一個參數傳遞給它。

該函數是一個高階函數的例子 傳遞給它的函數稱為 callback - 另一個函數執行完畢後要執行的函數。

假設我們向 API 發送了一個請求,以返回我們帳戶中最喜歡的照片。我們可能需要等待響應,因為 API/服務可能會在返迴響應之前進行一些計算。

這可能需要很長時間,並且我們不想在等待響應時凍結線程。相反,我們將創建一個回調,當響應到來時會收到通知。

在那之前,其餘的代碼都在執行,比如顯示帖子和通知。

如果您曾經使用過回調,那麼您很有可能經歷過回調地獄:

doSomething(function(x) {
    console.log(x);
    doSomethingMore(x, function(y) {
        console.log(y);
        doRestOfTheThings(y, function(z) {
            console.log(z);
        });
    });
});

想像一下,我們請求服務器獲取多個資源——一個人、他們的朋友和他們朋友的帖子、每個朋友帖子的評論、回復等。

管理這些嵌套的依賴關係很快就會失控。

我們可以使用 Promise 避免回調地獄並處理異步調用 s.

創建承諾

Promise s,顧名思義,是一個函數“給出它的話”,一個值將在以後返回。如果我們期望響應的函數沒有傳遞,它是一個可能不會返回的值的代理。

這些異步函數不是返回具體值,而是返回一個 Promise 對象,在某些時候會被實現或不被實現。

大多數情況下,在編碼時,我們會使用 Promise s 而不是創建它們。它是創建 Promise 的庫/框架 s供客戶消費。

儘管如此,了解創建 Promise 背後的原因還是很不錯的 :

let promise = new Promise(function(resolve, reject) {
    // Some imaginary 2000 ms timeout simulating a db call
    setTimeout(()=> {
        if (/* if promise can be fulfilled */) {
            resolve({msg: 'It works', data: 'some data'});
        } else {
            // If promise can not be fulfilled due to some errors like network failure
            reject(new Error({msg: 'It does not work'}));
        }
    }, 2000);
});

Promise 構造函數接收一個參數 - 一個回調。回調可以是常規函數或箭頭函數。回調有兩個參數 - resolvereject .兩者都是函數引用。回調也稱為執行者。

創建 Promise 後,executor 會立即運行。通過調用 resolve() 解決承諾 如果 promise 被履行,並通過調用 reject() 被拒絕 如果不能實現的話。

resolve()reject() 接受一個參數 - boolean , string , number , array , 或 object .

消費承諾

通過 API,假設我們從服務器請求了一些數據,但不確定何時返回——是否會返回。這是我們何時使用 Promise 的完美示例 來幫助我們。

假設處理我們調用的服務器方法返回一個 Promise ,我們可以消費它:

免費電子書:Git Essentials

查看我們的 Git 學習實踐指南,其中包含最佳實踐、行業認可的標準以及隨附的備忘單。停止谷歌搜索 Git 命令並真正學習 它!

promise.then((result) => {
    console.log("Success", result);
}).catch((error) => {
    console.log("Error", error);
})

如我們所見,我們鏈接了兩個方法 - then()catch() .這些是 Promise 提供的各種方法中的幾個 對象。

then() 當事情進展順利時執行,即由 resolve() 履行承諾 方法。如果 promise 被拒絕,catch() 將調用方法並將錯誤發送到 reject .

鍊式承諾

如果我們有一系列的異步任務一個接一個地需要執行——嵌套越多,代碼就越混亂。

這會導致我們陷入回調地獄,這可以通過鏈接多個 then() 輕鬆避免 單個 Promise 上的方法 d 結果:

promise.then(function(result) {
    // Register user
    return {account: 'blahblahblah'};
}).then(function(result) {
    // Auto login
    return {session: 'sjhgssgsg16775vhg765'};
}).then(function(result) {
    // Present WhatsNew and some options
    return {whatsnew: {}, options: {}};
}).then(function(result) {
    // Remember the user Choices
    return {msg: 'All done'};
});

我們可以看到結果是通過 then() 鏈傳遞的 處理程序:

  • 初始promise 對象解析
  • 然後是 then() 調用處理程序來註冊用戶
  • 它返回的值被傳遞給下一個then() 自動登錄用戶的處理程序
  • ...等等

此外,then(handler) 可以創建並返回一個承諾。

注意: 雖然技術上我們可以 做一些類似前面例子的事情,它可以遠離鏈接點。雖然這種技術在您需要選擇性地調用異步方法時很有用:

let promise = new Promise(function(resolve, reject) {
    setTimeout(() => resolve({msg: 'To do some more job'}), 1000);
});

promise.then(function(result) {
    return {data: 'some data'};
});

promise.then(function(result) {
    return {data: 'some other data'};
});

promise.then(function(result) {
    return {data: 'some more data'};
});

我們在這裡所做的只是將幾個處理程序添加到一個 Promise 中,所有這些處理程序都處理 result 獨立地。他們沒有按順序將結果相互傳遞。

這樣,所有的處理程序都會得到相同的結果——承諾的結果——{msg: 'To do some more job'} .

結論

Promise s,顧名思義,是一個函數“給出它的話”,一個值將在稍後的時間點返回。如果我們期望響應的函數沒有傳遞,它是一個可能不會返回的值的代理。

這些異步函數不是返回具體值,而是返回 Promise 對象,在某些時候會被實現或不被實現。

如果您使用過回調,您必須欣賞 Promise 的簡潔明了的語義 s.

作為一名 Node/JavaScript 開發人員,我們將更頻繁地處理 Promise。畢竟這是一個異步的世界,充滿了驚喜。


Tutorial JavaScript 教程
  1. 跳過本地開發的 Auth0 同意提示

  2. 與 Vue.js 相關的精彩內容的精選列表

  3. 遞歸介紹(第 2 部分實用)

  4. 如何使用 React 構建客戶支持實時聊天小部件

  5. JavaScript TypeOf – 如何在 JS 中檢查變量或對象的類型

  6. 在 React JS 中創建唯一 ID

  7. 使用 WEBRTC 對等安全地共享文件

  1. 與 Jhey Tompkins 配對

  2. 如果你知道 jQuery Focuspoint,你會喜歡 Vanilla Focus

  3. 帶有 VueJS 的 Ionic 框架:帶有身份驗證流程的拆分視圖菜單,使用 Vuex 和 Vue 組合

  4. 重播和異步主題(Observables)

  5. 使用 RxJS 操作符來消費 Observables

  6. 使用 Svelte 和 Firebase 構建無服務器聊天應用程序(第 2 部分)

  7. MrCodeDev 是誰,他將在 Dev.to 上做什麼?

  1. 將 Material UI CSS 框架添加到 React 應用程序

  2. 什麼是環境變量以及如何在 Gatsby 和 Netlify 中使用它們?

  3. 基本的 ReactJS 面試問題

  4. 面向新 JavaScript 軟件工程師的資源(2020 年)