由於js語言的特性,使用node開發程序的時候常常會遇到異步處理的問題。對於以前專長App開發的我來講,會糾結node中實現客戶端API請求的「最佳實踐」。下面以OAuth2.0爲場景,須要處理的流程:javascript
一開始,咱們使用了閉包嵌套閉包的方式實現,形如: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
能夠猜測 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對象: 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,所以能夠鏈式調用。