由使用request-promise-native想到的非同步處理方法

来源:https://www.cnblogs.com/scorpiozj/archive/2019/02/16/10388912.html
-Advertisement-
Play Games

由使用request-promise-native想到的非同步處理方法 問題場景 因為js語言的特性,使用node開發程式的時候經常會遇到非同步處理的問題。對於之前專長App開發的我來說,會糾結node中實現客戶端API請求的“最佳實踐”。下麵以OAuth2.0為場景,需要處理的流程: 處理過程 一開始 ...


由使用request-promise-native想到的非同步處理方法

問題場景

因為js語言的特性,使用node開發程式的時候經常會遇到非同步處理的問題。對於之前專長App開發的我來說,會糾結node中實現客戶端API請求的“最佳實踐”。下麵以OAuth2.0為場景,需要處理的流程:

  1. 獲取access token
  2. 使用獲取到的token,發起API請求
  3. 處理API數據

處理過程

一開始,我們使用了閉包嵌套閉包的方式實現,形如:

request(options, (res, error)=>{
    //handle res and error
    request(options2, (res2, error2)=>{
        //handle res2 and error2
    })
})

 

我們可以允許函數的非同步執行,但大多數人在思考問題的時候,尤其在解決如上的場景時,還是希望能採用線性地處理方式。於是,我們使用request-promise-native,配合aync/await,類似:

1 (async ()=> {
2     let access = await requestpromise(authoptions).then((value)=>{
3         return value;
4     }).catch((error)=>{
5         return error;
6     });
7     console.log('access', access);
8 })();

 

使用async/await的時候,需要知道:

  1. await不能單獨使用,其所在的上下文之前必須有async
  2. await 作用的對象是Promise對象

可以猜想 request-promise-native 必定是對request進行了Promise化,從源代碼中可以看到(雖然我沒看懂,應該是使用了通用的方法來創建Promise):

// Exposing the Promise capabilities
var thenExposed = false;
for ( var i = 0; i < options.expose.length; i+=1 ) {
    var method = options.expose[i];
    plumbing[ method === 'promise' ? 'exposePromise' : 'exposePromiseMethod' ](
        options.request.Request.prototype,
        null,
        '_rp_promise',
        method
    );
    if (method === 'then') {
        thenExposed = true;
    }
}
if (!thenExposed) {
    throw new Error('Please expose "then"');
}

 

既然如此,我們可以構造Promise,交給await。下麵就把request包裹成一個Promise:

 1 //token.js
 2 module.exports.getAccessToken =  async (options) => {
 3     return new Promise(function (resolve, reject) {
 4         request(options, function (error, res, body) {
 5           if (!error && res.statusCode == 200) {
 6             resolve(body);
 7           } else {
 8               if(error){
 9                   reject(error);
10               }else{
11                 reject(body);
12               }
13           }
14         });
15     });
16 };
17 //app.js
18 (async ()=> {
19     let access = await token.getAccessToken(authoptions).then((value)=>{
20         //handle value if requires
21         return value;
22     }).catch((error)=>{
23         return error;
24     });
25     console.log('access', access);
26     //use token to send the request
27 })();

 

API成功返回的結果我們往往需要按需處理,這一步放在then函數中進行。因為Promise調用then仍然是Promise,因此這裡鏈式調用的then和catch。
進一步地,我們嘗試使用內置模塊 util 對函數進行promise化,形如:

//token.js
const request = require('request');
const {promisify} = require('util');
const requestPromise = promisify(request);
module.exports.getAccessToken =  async (options) => {
    return requestPromise(options);
};
//app.js
(async ()=> {
    let access = await token.getAccessToken(authoptions).then((value)=>{
        //handle value if requires
        return value;
    }).catch((error)=>{
        return error;
    });
    console.log('access', access);
    //use token to send the request
})();

 

說了這麼多,對我而言,目前最大的收穫就是理解瞭如何使用Promise/async/await,把非同步函數順序執行:把帶有閉包的函數包裹進Promise,然後使用async/await執行該Promise。

好了,以上是我解決此類問題的思路。我相信必然還有其他優雅的解決方式,甚至是最佳實踐。今天,藉此機會,拋磚引玉,希望大家能夠不吝賜教。

Promise 內容複習

最後,容我溫習一下Promise相關的內容,有片面的地方請大家指正。
Promise對象:

The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.

Promise有三種狀態: 初始狀態,執行成功,執行出錯。 then()表示promise執行後的進一步處理,它可以帶兩個callback參數:第一個用於promise成功運行後執行,第二個表示promise運行失敗後執行。catch()表示promise運行失敗後所執行的工作。catch()可以理解為語法糖,當then()的第二個callback參數省略的時候,意味著需要調用catch(因為未處理的失敗的promise在將來某個node版本會導致程式退出)。需要註意的是,then()/catch()方法也是返回Promise,因此可以鏈式調用。

參考

Promise-MDN web docs
用圖表和實例解釋 Await 和 Async

javascript 學習: async await


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 目前市面上的PC電腦主要運行著四大類系統,它們分別是微軟的Windows、蘋果的MacOS、Linux的發行版以及Unix類系統。其中Linux和Unix都是開源的,因此市面出現的眾多基於Linux內核和Unix內核的發行版系統,其中Linux類系統數量最多、用戶基數大,廣泛使用於各行各業。相 ...
  • 1. 概述 1. 不同的操作系統, 對於 換行, 有不同的表示 2. 不算是很重要, 但有時候也會製造些小麻煩 2. 換行 1. lf 1. 名稱 1. linefeed 2. 轉義字元 1. \n 2. cr 1. 名稱 1. carriage return 2. 轉義字元 1. \r 3. 操作 ...
  • 背景 ​ 回顧人們在開始工作之前,都會問自己這樣一個問題:給你一臺16G記憶體的Innodb專用資料庫伺服器,如何配置才能讓其穩定、高效地給典型的Web應用提供服務? 硬體 記憶體:記憶體對於Innodb資料庫至關重要!16 32G記憶體 CPU:雖然CPU配置依賴於應用,但一般來說,就CPU來說,2 Du ...
  • 第一步:下載Tomcat8壓縮包 進入 http://tomcat.apache.org/download-80.cgi 下載tar.gz壓縮包 第二步:用ftp工具把壓縮包上傳到/home/data/下 第三步:解壓以及新建目錄 [root@localhost ~]# ls /home/data/ ...
  • --查詢資料庫邏輯文件名 USE 資料庫名 SELECT FILE_NAME(1) --查詢資料庫邏輯文件名(日誌) USE 資料庫名 SELECT FILE_NAME(2) --附加資料庫 sp_attach_db '資料庫名','資料庫全路徑','資料庫日誌全路徑' GO USE 資料庫名 -- ...
  • 什麼是組件化 不用去糾結組件和模塊語義上的區別,如果模塊間不存在強依賴且模塊間可以任意組合,我們就說這些模塊是組件化的。 組件化的好處 1. 實現組件化本身就是一個解耦的過程,同時也在不斷對你的項目代碼進行提煉。對於已有的老項目,實現組件化剛開始是很難受的,但是一旦組件的框架初步完成,對於後期開發效 ...
  • 一、效果圖 二、思路 1. 定義兩個 CSS 過度動畫,前進與後退: slide-right-enter 和 slide-left-enter 2. 給路由配置meta信息,設置各個路由的級別: index 3. 監控路由跳轉,比對 meta 信息級別,如果從大跳轉到小說明是返回,從小跳轉到大則是前 ...
  • Vue完成 TodoList 1.預設方式 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>TodoList</title> <script src="../../vue.js"></script> </he ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...