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

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

問題場景

由於js語言的特性,使用node開發程序的時候常常會遇到異步處理的問題。對於以前專長App開發的我來講,會糾結node中實現客戶端API請求的「最佳實踐」。下面以OAuth2.0爲場景,須要處理的流程:javascript

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

處理過程

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

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

 

咱們能夠容許函數的異步執行,但大多數人在思考問題的時候,尤爲在解決如上的場景時,仍是但願能採用線性地處理方式。因而,咱們使用request-promise-native,配合aync/await,相似:java

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的時候,須要知道:node

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

能夠猜測 request-promise-native 一定是對request進行了Promise化,從源代碼中能夠看到(雖然我沒看懂,應該是使用了通用的方法來建立Promise):web

// 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: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。app

好了,以上是我解決此類問題的思路。我相信必然還有其餘優雅的解決方式,甚至是最佳實踐。今天,藉此機會,拋磚引玉,但願你們可以不吝賜教。異步

Promise 內容複習

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

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

相關文章
相關標籤/搜索