zoukankan      html  css  js  c++  java
  • 由使用request-promise-native想到的异步处理方法

    由使用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

  • 相关阅读:
    2019南京网络赛 D Robots 期望dp
    【ICPC2019银川站】K
    【ICPC2019南昌站】I
    【SEERC 2019】E
    电子取证知识和经验总结
    CCPC2020绵阳站游记
    【CCPC2020绵阳站】J
    【CCPC2020绵阳站】K
    【SWERC 2019-20】K Birdwatching
    【HAOI2012】容易题
  • 原文地址:https://www.cnblogs.com/scorpiozj/p/10388912.html
Copyright © 2011-2022 走看看