前言
随着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);
});
}
}
});