大家会用 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规范。
functionr() {let task = {}const promise =newPromise((resolve) => {let timertask.abort =function() {clearTimeout(timer)}timer = setTimeout(() => {resolve()}, 1000)})promise.task = taskreturnpromise}functiona() {returnr()}varpromise = a()promise.then(res => {console.log(1)})promise.task.abort()a().then(res => {console.log(2)})demo实现思路,挂载在返回的promise上,但会有问题,你可以看到在调用的时候需要手动声明一个promise变量,不能直接a().then() 因为then返回的是一个新的Promise,上面没有挂载的task。
今天遇到了这个问题,在不影响从前的代码的情况下想出来的。更好的思路暂时没有。这里就抛砖引玉了
因为是异步函数,获取服务器数据时会出现几秒至几十秒的延迟,
在渲染页面的时候如果要用到服务器数据的可能获取不到,
一个常用的解决方式是所有涉及到服务器数据的变量都要进行初始化,并且页面加载的时候用loading提示
--------
调用:
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> {varrequestTask: WechatMiniprogram.RequestTask;varp =newResponsePromise<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(newHttpError(res.statusCode, res.header, res.data));}},fail(err) {reject(newError(err.errMsg));}});}catch(e) {reject(e);}});p.requestTask = requestTask;returnp;}public static getAsync<T>(url: string, data?: string | DatasObject | ArrayBuffer, header?: HeadersObject): ResponsePromise<T> {returnRequest.ExecAsync<T>({ url: url, data: data, header: header, method:"GET"});}public static postAsync<T>(url: string, data?: string | DatasObject | ArrayBuffer, header?: HeadersObject): ResponsePromise<T> {returnRequest.ExecAsync<T>({ url: url, data: data, header: header, method:"POST"});}public static deleteAsync<T>(url: string, data?: string | DatasObject | ArrayBuffer, header?: HeadersObject): ResponsePromise<T> {returnRequest.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();}}