如何优雅的让小程序的request请求支持callback & Promise的写法

metal 1年前 ⋅ 1317 阅读
ad

前言

随着Promise在被广泛的使用和解决回调地狱的问题,以至于我们只要在发ajax请求的时候就会想起来去使用它。最近在使用小程序的请求request就想当然的使用then的方式来获取结果,然并卵。。。

就去小程序官网巴拉下资料小程序文档链接, 仔细翻阅得到结果如下:

异步 API 返回 Promise

基础库 2.10.2 版本起,异步 API 支持 callback & promise 两种调用方式。当接口参数 Object 对象中不包含 success/fail/complete 时将默认返回 promise,否则仍按回调方式执行,无返回值。

注意事项:部分接口如 request 等等, 它们的 promisify 需要开发者自行封装

那么我们就来对request 封装,使它支持callback & promise 两种调用方式

一、关于Promise的一些基本介绍和使用

此处只是简单的概述一些基本理念和表现形势,以帮助能理解后续的实现(没有基础的同学,自行度娘和google)

Promise 对象用于一个异步操作的最终完成(或失败)及其结果值的表示。简单点说,它就是用于处理异步操作的,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作。

一般表示形式为:

new Promise(
    /* executor */
    function(resolve, reject) {
        if (/* success */) {
            // ...执行代码
            resolve();
        } else { /* fail */
            // ...执行代码
            reject();
        }
    }
);

 

二、关于Object.defineProperty的简单描述,(后面会对request重新定义需要用到对象的该方法)

解释:

Object.defineProperty() 会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

语法:

Object.defineProperty(obj, prop, descriptor)
obj:要定义属性的对象。
prop:要定义或修改的属性的名称
descriptor:属性描述符。

用法:

const obj = {};

Object.defineProperty(obj, 'age', {
    value: 24,
    writable: false
});

console.log(obj.age);

// expected output: 42

//对象obj拥有了属性age,值为24

属性描述符说明:

configurable: 当且仅当configurable为true时,改属性描述符才能够被改变,也能被删除
enumerable: 当其值为true时,该属性才能够出现在对象的枚举属性中,默认为false
writable: 当且仅当该属性的值为true时,该属性才能被赋值运算符改变, 默认为false。
value: 该属性对应的值,可以是任意有效的javascript的值(数值,对象,函数等),默认为undefined

*个人尝试,writable为false时也是可以赋值的,可参考上面案例。

三、尝试对小程序的Request方法的一些属性的修改

首先要保证原始对象的一些原有方法和属性不能被改变,所以需要先保存原始对象,然后克隆新对象

通过上述第二点Object.defineProperty 的方法来修改现有的属性,在请求之前、成功和失败之后处理

具体实现的代码如下:

//接收原对象
const originWx = wx;
//基于WX创建个新对象
wx = Object.create(wx);

//下面尝试对wx.request一些成功失败进行尝试改写
Object.defineProperty(wx, 'request', {
    writable: false,
    value: function(e) {
        console.log('request start...', e);
        // do  something ....
        const success = arguments[0].success;
        const fail = arguments[0].fail;
        //对成功的方法重写定义
        arguments[0].success = function(...args) {
            console.log('request success');
            // do  something .... 
            success(...args); 
        }
        //对失败的方法重写定义
        arguments[0].fail = function(...args) {
            console.log('request fail');
            // do  something .... 
            fail(...args); 
        }
        //确保原来的request执行
        originWx['request'].apply(this, arguments);
    }
});

 

四、通过Promise来实现request能同时满足callback和then的使用

如何让request能满足then的使用,我们先来看看request最原始的用法

wx.request({
  url: 'example.php', //仅为示例,并非真实的接口地址
  data: {
    x: '',
    y: ''
  },
  header: {
    'content-type': 'application/json' // 默认值
  },
  success (res) {
    console.log(res.data)
  },
  fail (err) {
    console.log(err)
  }
})

那么要能同时到达wx.request({url, data, header}).then()的使用和原始的使用改如何分析呢?

通过上述的标黄调用方式,不难发现request的请求参数options对象里面是不包含 success

那么我们是否可以通过是否有success回调函数来区别处理

没有success回调,那么then该怎么实现呢,这时候就该我们Promise出场了,在没有回调函数的时候,我们是否可以直接返回一个Promise

最终改版后的代码实现如下:

//接收原对象
const originWx = wx;
//基于WX创建个新对象
wx = Object.create(wx);

//下面尝试对wx.request一些成功失败进行尝试改写
Object.defineProperty(wx, 'request', {
    writable: false,
    value: function(e) {
        console.log('request start...', e);
        // do  something ....
        const success = arguments[0].success;
        if (success) {
            const fail = arguments[0].fail;
            //对成功的方法重写定义
            arguments[0].success = function(...args) {
                console.log('request success');
                // do  something .... 
                success(...args); 
            }
            //对失败的方法重写定义
            arguments[0].fail = function(...args) {
                console.log('request fail');
                // do  something .... 
                fail(...args); 
            }
            //确保原来的request执行
            originWx['request'].apply(this, arguments);
       } else {
           //没有回调走promise
            return new Promise((resolve, reject) => {
                //没有传内部给定一个success回调
                arguments[0].success = function(...args) {
                    console.log('request promise success');
                    // do  something .... 
                    resolve(...args); 
                }
                //没有传内部给到一个fail回调
                arguments[0].fail = function(...args) {
                    console.log('request promise fail');
                    // do  something .... 
                    reject(...args); 
                }
                //确保原来的request执行
                originWx['request'].apply(this, arguments);
            });
       }
    }
});

 

 

关于Webfunny

Webfunny专注于前端监控系统,前端埋点系统的研发。 致力于帮助开发者快速定位问题,帮助企业用数据驱动业务,实现业务数据的快速增长。支持H5/Web/PC前端、微信小程序、支付宝小程序、UniApp和Taro等跨平台框架。实时监控前端网页、前端数据分析、错误统计分析监控和BUG预警,第一时间报警,快速修复BUG!支持私有化部署,Docker容器化部署,可支持千万级PV的日活量!

  点赞 0   收藏 0
  • metal
    共发布8篇文章 获得0个收藏
全部评论: 0