大家会用 promise 将 wx.request 包装一层。但经过这么一层包装后,就拿到不到 requestTask,从而调用不了 abort 方法。大家都是如何解决的? 代码来自:https://www.kancloud.cn/xiaoyulive/wechat/526990
class Request { constructor (parms) { this .withBaseURL = parms.withBaseURL this .baseURL = parms.baseURL } get (url, data) { return this .request( 'GET' , url, data) } post (url, data) { return this .request( 'POST' , url, data) } put (url, data) { return this .request( 'PUT' , url, data) } request (method, url, data) { const vm = this return new Promise((resolve, reject) => { wx.request({ url: vm.withBaseURL ? vm.baseURL + url : url, data, method, success (res) { resolve(res) }, fail () { reject({ msg: '请求失败' , url: vm.withBaseURL ? vm.baseURL + url : url, method, data }) } }) }) } } const request = new Request({ baseURL: 'http://test' , withBaseURL: true }) module.exports = request |
function request(opt) { return new Promise((success, fail) => { const requestTask = wx.request({ ...opt, success, fail, }); opt.signal && (opt.signal.onabort = () => requestTask.abort()) }) } // usage const signal = {}; request({ url: "localhost", signal: signal }).then(response => console.debug(response)).catch(error => console.error(error)); signal.onabort();
设计思路来源于 fetch AbortSignal
由于小程序没有事件系统🙄,使用onabort粗暴处理了。可根据需要自己编写事件系统使程序更加贴合web规范。
function
r() {
let task = {}
const promise =
new
Promise((resolve) => {
let timer
task.abort =
function
() {
clearTimeout(timer)
}
timer = setTimeout(() => {
resolve()
}, 1000)
})
promise.task = task
return
promise
}
function
a() {
return
r()
}
var
promise = a()
promise.then(res => {
console.log(1)
})
promise.task.abort()
a().then(res => {
console.log(2)
})
demo实现思路,挂载在返回的promise上,但会有问题,你可以看到在调用的时候需要手动声明一个promise变量,不能直接a().then() 因为then返回的是一个新的Promise,上面没有挂载的task。
今天遇到了这个问题,在不影响从前的代码的情况下想出来的。更好的思路暂时没有。这里就抛砖引玉了
--------
调用:
https://github.com/xdoer/PreQuest/blob/main/packages/miniprogram/src/adapter.ts
可以看看这个源码,采用了 axios 的 cancel-token 的思想。
function request(url, opt){ const { getNativeRequestInstance } = opt return new Promise(() => { let resolvePromise: any let promise = new Promise(resolve => (resolvePromise = resolve)) getNativeRequestInstance(promise) const instance = wx.request({ // ... 参数 }) resolvePromise(instance) }) }
用法如下:
const req = await request('/api', { getNativeRequestInstance(promise) { promise.then(instance => { instance.abort() }) } })
挖坟看到这了,有一个思路是返回两个值。 如:
let(asyncTask,asyncController) = request(...);
asyncTask.then(res=>...);
asyncController.abort();
===
代码开源在这,有增强的朋友可以在增强
https://git.weixin.qq.com/jiji-opensouce/wx-xcx-empty-template/blob/master/utils/restapi.js
function request(params) { const { url, method, header, data } = params let taskController; let task = new Promise((resolve, reject) => { taskController = wx.request({ url, header, data, method, success(res) { resolve(res) }, fail(err) { reject({ msg: '请求失败', url, method, data, header, err, }) } }) }); return { task, taskController }; } // 使用 示例 request({ url: "http://www.qq.com", method: "GET" }).task.then(res=> console.log(res)); request({ url: "http://www.qq.com", method: "GET" }).taskController.abort();
consr { task, taskController } = request({ url: "http://www.qq.com", method: "GET" })
taskController.abort()
/** * 微信wx.Request 请求接口的附加值 */ export interface PromiseWxResponse<T> extends Promise<T> { /** * Response对象 */ wxResult?: WechatMiniprogram.RequestSuccessCallbackResult, /** * 微信wx.Request 的实例 */ wxRequestTask?:WechatMiniprogram.RequestTask }
/** * 统一的HTTP请求入口 * @param options {string | RequestOption} url 接口地址 或者 RequestOption 对象 * @param needLoginCallback 登录拦截的callback方法。当接口数据返回成功、且code是401时,将执行needLoginCallback * @returns {PromiseWxResponse<*> */ export const request = (options: RequestWxOption): PromiseWxResponse<any> => { const promise: PromiseWxResponse<any> = new Promise((resolve, reject) => { const requestTask:WechatMiniprogram.RequestTask = wx.request(<WechatMiniprogram.RequestOption>{ url: options.url, method: options.method, data: options.data, header: options.header, success: (result: WechatMiniprogram.RequestSuccessCallbackResult) => { promise.wxRequestTask = requestTask; promise.wxResult = result; resolve(data);e { } }, fail: (result: WechatMiniprogram.GeneralCallbackResult) => { promise.wxRequestTask = requestTask; reject(result); } }); }); return promise; };
个人感觉最好不要对返回的Promise做修改不然下游的流程处理都会变得繁琐起来
可以借助web规范里的AbortSignal,或着更简单方法是在入口参数加个配置项:
onCancel?: (cancel: () => void) => void
ts源码:
export namespace Hz.Http {
const ES6Promise = require(
'es6-promise'
);
export interface DatasObject {
[data: string]: number | string | string[] | undefined;
}
export interface HeadersObject {
[header: string]: number | string | string[] | undefined;
}
export interface RequestParams {
url: string;
method?: string;
dataType?: string;
data?: string | DatasObject | ArrayBuffer;
header?: HeadersObject;
responseType?: string;
}
export class HttpError extends Error {
public statusCode: number;
public header: HeadersObject;
public body: string | object | ArrayBuffer;
constructor(statusCode: number, header: HeadersObject, body: string | object | ArrayBuffer) {
super
(`response status code: ${statusCode}`);
this
.statusCode = statusCode;
this
.header = header;
this
.body = body;
}
}
export class ResponsePromise<T> extends ES6Promise<T> {
public statusCode: number;
public header: HeadersObject;
public body: string | object | ArrayBuffer;
public requestTask: WechatMiniprogram.RequestTask;
constructor(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) {
super
(executor);
}
public onHeadersReceived(callback: WechatMiniprogram.RequestTaskOnHeadersReceivedCallback) {
this
.requestTask.onHeadersReceived(callback);
}
public offHeadersReceived(callback: WechatMiniprogram.RequestTaskOffHeadersReceivedCallback) {
this
.requestTask.offHeadersReceived(callback);
}
public abort(): void {
this
.requestTask.abort();
}
}
export class Request {
public static ExecAsync<T>(pars: RequestParams): ResponsePromise<T> {
var
requestTask: WechatMiniprogram.RequestTask;
var
p =
new
ResponsePromise<T>((resolve, reject) => {
try
{
requestTask = wx.request({
url: pars.url,
data: pars.data,
header: pars.header,
method: pars.method,
dataType: pars.dataType,
responseType: pars.responseType,
success(res) {
if
(res.statusCode >= 200 && res.statusCode < 300) {
p.statusCode = res.statusCode;
p.header = res.header;
p.body = res.data;
resolve(res.data);
}
else
{
reject(
new
HttpError(res.statusCode, res.header, res.data));
}
},
fail(err) {
reject(
new
Error(err.errMsg));
}
});
}
catch
(e) {
reject(e);
}
});
p.requestTask = requestTask;
return
p;
}
public static getAsync<T>(url: string, data?: string | DatasObject | ArrayBuffer, header?: HeadersObject): ResponsePromise<T> {
return
Request.ExecAsync<T>({ url: url, data: data, header: header, method:
"GET"
});
}
public static postAsync<T>(url: string, data?: string | DatasObject | ArrayBuffer, header?: HeadersObject): ResponsePromise<T> {
return
Request.ExecAsync<T>({ url: url, data: data, header: header, method:
"POST"
});
}
public static deleteAsync<T>(url: string, data?: string | DatasObject | ArrayBuffer, header?: HeadersObject): ResponsePromise<T> {
return
Request.ExecAsync<T>({ url: url, data: data, header: header, method:
"DELETE"
});
}
}
}
//使用方法:
(async () => {
try {
var data = await Hz.Http.Request.getAsync("http://localhost/");
var p = Hz.Http.Request.getAsync("http://localhost/");
var body = await p;
var code = p.statusCode;
var header = p.header;
p.abort();
}
catch (e) {
// 非 200 - 299 的状态码
if (e instanceof Hz.Http.HttpError) {
console.log(e.statusCode, e.header, e.body, e.message);
}
else if (e instanceof Error) {
console.log(e.message);
}
else {
console.log(e);
}
}
})();
export class ResponsePromise<T> extends ES6Promise<T> {
public statusCode: number;
public header: HeadersObject;
public body: string | object | ArrayBuffer;
public requestTask: WechatMiniprogram.RequestTask;
constructor(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) {
super(executor);
}
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): ResponsePromise<T> {
super.then(onfulfilled, onrejected);
return this;
}
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): ResponsePromise<T> {
super.then(onrejected);
return this;
}
public onHeadersReceived(callback: WechatMiniprogram.RequestTaskOnHeadersReceivedCallback) {
this.requestTask.onHeadersReceived(callback);
}
public offHeadersReceived(callback: WechatMiniprogram.RequestTaskOffHeadersReceivedCallback) {
this.requestTask.offHeadersReceived(callback);
}
public abort(): void {
this.requestTask.abort();
}
}