0.0.1 • Published 3 years ago

base-request-queue v0.0.1

Weekly downloads
-
License
ISC
Repository
-
Last release
3 years ago

TOC

一、配置

通过调用 RequestQueue.setConfig() 对 RequestQueue 进行全局配置。此选项可选,如果未配置则会使用默认的配置。

其他配置项请看源码。

RequestQueue.setConfig(() => {
    let rc = new RequestConfig();
    rc.addDataParser(new DefaultDataParser())
    rc.setTask(new AxiosTaskImpl());
    return rc;
});

注:推荐在项目的入口进行初始化

二、使用方法

1. 最简单的请求

发起一个简单的 GET 请求,不考虑是否成功与失败。

RequestQueue.create(this).request(Request.get<string>("url"));

2. 标准的请求

发起一个标准的 GET 请求,参数是 id=123,成功或失败的时候打印一条消息

RequestQueue.create(this)
    .request(Request.get<string>("url")
        .setData({id: "123"})
        .setSuccessListener((data: string) => Logger.log(TAG, "success"))
        .setFailListener((error: any) => Logger.log(TAG, "fail"))
    );

3. 发起多个请求(由每个 Request 处理结果)

由每个 Request 单独处理 成功/失败 回调。

// 同时请求两个接口
RequestQueue.create(this)
    .addRequest(Request.get<T>("url-1").setSuccessListener((data: T) => this.data1 = data))
    .addRequest(Request.get<T>("url-2").setSuccessListener((data: T) => this.data2 = data))
    .setFailListener((error: any) => console.log("error"))
    .request()

如果是多个网络请求,必须使用 addRequest 添加,再调用 request 执行请求队列。

注:此时的 request() 不能传值

4. 发起多个请求(统一由 RequestQueue 处理结果)

统一由 RequestQueue 来处理 成功/失败 回调。

// 同时请求两个接口
RequestQueue.create(this)
    .addRequest(Request.get<T>("url-1"))
    .addRequest(Request.get<T>("url-2"))
    // 每个接口成功后都会执行一次 successListener 监听,可以通过判断 url 来区别不同的接口
    .setSuccessListener((data: any, result: ResponseEntity<any>) => {
        if (result.request.getUrl() === "url-1") {
            this.data1 = data as string;
        } else if (result.request.getUrl() === "url-1") {
            this.data2 = data as number;
        }
    })
    .setFailListener((error: any) => console.log("error"))
    .setCompleteListener(() => {})
    .request()

交给 RequestQueue 后,每次执行完一个 Request 后,RequestQueue.setSuccessListener() 都会被触发一次,可以在该方法内部统一处理所有请求的数据,直至所有请求完成。同理,如果出现请求失败的情况会触发 RequestQueue.setFailListener() 方法,同时终止其他未完成的 Request。

这里需要说明的是 RequestQueue.setCompleteListener() 不管请求成功还是请求失败到最后都会执行,可以在该方法内做一些收尾工作。

5. 并行执行所有请求

这是默认的方式,不做任何设置就是并行,如果想切换到并行只需要在 addRequest 前调用 belowParallel() 即可。

RequestQueue.create(this)
    .addRequest(Request.get<string>("url"))
    .addRequest(Request.get<string>("url"))
    .request();

6. 串行执行所有请求

如果想切换到并行只需要在 addRequest 前调用 belowSerial() 即可。

RequestQueue.create(this)
    .belowSerial() // 并行执行下面的请求
    .addRequest(Request.get<T>("url"))
    .addRequest(Request.get<T>("url"))
    .request();

7. 执行组合请求

通过 belowParallel()belowSerial() 可依据项目需求自由组合多个网络请求。

RequestQueue.create(this)
    .belowParallel() // 并行执行下面的请求
    .addRequest(Request.get<T>("url"))
    .addRequest(Request.get<T>("url"))
    .belowSerial()   // 串行执行下面的请求
    .addRequest(Request.get<T>("url"))
    .addRequest(Request.get<T>("url"))
    // 处理状态
    .setSuccessListener((data: any) => Logger.log(TAG, "success"))
    .setFailListener((error: any) => Logger.log(TAG, "fail"))
    .setCompleteListener(() => Logger.log(TAG, "complete"))
    .request();

三、自定义 DataParser 和 Task

1. 自定义 DataParser

RequestQueue 提供一个默认的 DefaultDataParser ,这个解析器仅仅是返回服务器的原始数据,不做任何处理。但通常情况下每个项目都会有一套自己的数据规范,此时可以通过实现 DataParser 接口来编写自己的解析器。

例如:

{
    code: 200,
    message: "测试数据",
    data: {
        name: "test"
    }
}

通过实现 DataParser 来编写自己的解析器,来完成对上面数据的解析。

isParserdataParser 是必须要实现的两个方法,第一个用来判断是否使用该解析器,第二个用来解析数据。

export default class TestDataParser<T> implements DataParser<T> {
    public isParser(result: any): boolean {
        if ("code" in result.data && "message" in result.data && "data" in result.data) {
            return true;
        }
        return false;
    }
    public dataParser(result: any, error: any,
                      success: (data: T) => void,
                      fail: (code: string, errorMessage: string, data?: T) => void): void {
        if (result) {
            if (String(result.status) === "200") {
                let data = result.data;
                if (String(data.code) === "200") {
                    success(result.data);
                } else {
                    fail(result.code, result.message, result);
                }
            } else {
                fail(result.status, "HTTP 错误", undefined);
            }
        } else if (error) {
            fail("-1", "HTTP Error", undefined);
        }
    }
}

编写完自定义的解析器后,只需通过 RequestConfig.addDataParser() 添加即可。

2. 自定义 Task

RequestQueue 提供一个默认的 AxiosTaskImpl ,基于 Axios 网络库,如果想在微信小程序、uni-app等其他平台使用,可以通过继承 TaskPerformerImpl 来实现自己的 Task。

createRequestrunAbort 是必须要实现的两个方法,第一个用来创建使用的网络库,第二个用来终止请求。

export default class AxiosTaskImpl<T> extends TaskPerformerImpl<T> {
    private axiosTask!: AxiosPromise<T>;
    private cancelTokenSource!: CancelTokenSource;

    protected createRequest<F>(url: string, method: RequestMethod, data: any, headers: any,
                               callback: (request: any, error: any) => void) {
        this.cancelTokenSource = axios.CancelToken.source();
        this.axiosTask = this.createStandardAxios(url, method, data, headers);
        this.axiosTask.then(result => {
            callback(result, null);
        });
        this.axiosTask.catch(error => {
            callback(null, error);
        });
    }

    protected runAbort() {
        if (this.axiosTask && this.cancelTokenSource) {
            this.cancelTokenSource.cancel("fail abort");
        }
    }

    private createStandardAxios(url: string, method: RequestMethod, data: any, headers: any): AxiosPromise<T> {
        let axio = axios({
            url: url,
            method: method,
            data: data,
            headers: headers,
            cancelToken: this.cancelTokenSource.token
        });
        return axio;
    }
}

四、结构

- interface: Task                               接口
  - abstract class: TaskPerformerImpl           基础的 Task 逻辑实现
    - class: AxiosTaskImpl                      Axios 的具体实现
- interface: TaskQueue                          队列模式
  - class: TaskQueueParallelImpl                并行模式具体实现
  - class: TaskQueueSerialImpl                  串行模式具体实现
- interface: DataParser                         数据解析器
  - class: DefaultDataParser                    返回原始数据
  - class: StringDataParser                     返回字符形式的原始数据
- class: RequestConfig                          配置文件
- class: Request                                请求体
- class: RequestQueue                           请求队列
- interface: RequestSuccessListener             成功回调
- interface: RequestFailListener                失败回调
- interface: RequestCompleteListener            完成回调
- interface: RequestUploadProgressListener      文件上传进度回调
- interface: RequestDownloadProgressListener    文件下载进度回调
- interface: RequestFrontListener               Request 前置回调

编写完自定义的 Task 后,只需通过 RequestConfig.setTask() 添加即可。

五、API

1. Request API

static get<T>(url: string): Request<T>

静态 创建一个 GET 请求

  • url: 请求地址
static post<T>(url: string): Request<T>

静态 创建一个 POST 请求

  • url: 请求地址
static put<T>(url: string): Request<T>

静态 创建一个 PUT 请求

  • url: 请求地址
static delete<T>(url: string): Request<T>

静态 创建一个 DELETE 请求

  • url: 请求地址
static head<T>(url: string): Request<T>

静态 创建一个 HEAD 请求

  • url: 请求地址
static options<T>(url: string): Request<T>

静态 创建一个 OPTIONS 请求

  • url: 请求地址
static patch<T>(url: string): Request<T>

静态 创建一个 PATCH 请求

  • url: 请求地址
setTag(tag: string): Request<T>

创建一个标记,用来区分 Request

setIgnore(isIgnore: () => boolean): Request<T>

在 RequestQueue 执行到此 Request 时,是否忽略此 Request

setIgnore() 接受一个返回类型是 boolean 的 Function

  • isIgnore: true 忽略,false 不忽略
setRetry(retry: number): Request<T>

重试次数,默认为 0

setRequestConfig(requestConfig: RequestConfig): Request<T>

无视,还未开发完

setTask(task: Task<T>): Request<T>

支持为每个 Request 设置单独的 Task,目前支持的 Task 有:

  • TaskAxiosImpl: 基于 axios 实现
  • TaskWxImpl: 基于小程序的 Request 实现
  • TaskUniImpl: 基于 UniApp 的 Request 实现

如果想根据不同的平台实现不同的 Task,只需要实现 Task 接口,然后编写逻辑代码即可。

setData(data: any): Request<T>

Request 的请求参数,data 类型为 any,可以传递各种类型的对象

例如:

{
    id: 111,
    user: "username",
    array: [1, 2, 3, ...],
    sArray: [{id: 1}, {id: 2}, ...]
}

[1, 2, 3, ...]

[{id: 1}, {id: 2}, ...]

注意:data 如果为 Object 类型,这时 value 会有一些隐性规定

  • 如果 value 为 null 或 undefined 时,Task 会将指定的 key 从请求体中删除
  • 如果 value 为 "",Task 不会处理

例如:

// 构建的参数
{
    id: 123,
    username: "",
    password: null
}
// Task 处理过后的数据
{
    id: 123,
    username: ""
}
setMethod(method: RequestMethod): Request<T>

设置 Request 的请求类型,通常情况下直接使用 Request.get... 相关方法即可,但在某些特殊的情况下,可以配合 setFrontListener() 来改变当前 Request 的请求类型

setHeaders(headers: Array<Header>): Request<T>

批量添加请求头

例如:

let headers: Array<Header> = new Array<Header>();
headers.push(new Header("key", "value"))
headers.push(new Header("key", "value"))
Request.get<string>("url").addHeader(headers)

注意:使用 setHeaders 时,会覆盖原有 Request 中的 headers

addHeader(key: string, value: string): Request<T>

添加一个请求头

setFrontListener(listener: Promise<RequestFrontListener<T>>): Request<T>

请求前置监听

setFrontListener 接受一个 Promise 对象,可以处理耗时任务,当处理耗时任务时,整个 RequestQueue 会停下来等待 front 的完成

例如:

Request.get<string>("url")
    // 假设 getWxCode 为异步函数,获取 code 需要 1 秒
    // 此时可以通过 front 函数,当 code 获取成功后再往下执行
    .setFrontListener(async (request: Request<string>) => {
        request.getData()["code"] = await this.getWxCode();
    }));

注意:此监听只在 TaskQueue 为 TaskQueueSerialImpl 时才会生效

setSuccessListener(listener: RequestSuccessListener<T>): Request<T>

请求成功监听

setFailListener(listener: RequestFailListener<T>): Request<T>

请求失败监听

public setDownloadProgressListener(listener: RequestDownloadProgressListener): Request<T>

文件下载进度监听

setUploadProgressListener(listener: RequestUploadProgressListener): Request<T>

文件上传进度监听

2. RequestQueue API

static create(context?: BaseVue): RequestQueue

静态 创建一个 RequestQueue 队列

  • context: 页面的上下文,每个页面必须继承自 BaseVue
setShowLoading(isShowloading: boolean, loadingTarget: string): RequestQueue

是否显示加载中动画

  • isShowloading: true 开启、false 关闭【默认 false】
  • loadingTarget: 在哪个 div 上面显示加载动画,不传默认是全屏,参数例子:"#app-layout"
setShowErrorMessage(isShowErrorMessage: boolean): RequestQueue

是否显示服务器返回的错误信息

  • isShowErrorMessage: true 开启、false 关闭【默认 true】
addRequest<T>(request: Request<T>): RequestQueue

将一个 Request 添加到队列中

request<T>(request?: Request<T>): void

执行请求队列

  • request 如果不传参数,将直接执行队列
  • request 如果传了参数,会创建一个队列并执行

注意:一旦使用了 addRequest() 方法,那 request() 的形参不能传

belowSerial<T>(): RequestQueue

添加一个串行队列

注意:在 belowSerial() 之后调用 addRequest(),请求会放入串行队列中

belowParallel<T>(): RequestQueue

添加一个并行队列

注意:在 belowParallel() 之后调用 addRequest(),请求会放入并行队列中


belowSerial() 和 belowParallel() 注意事项:

每个 RequestQueue 都有一个主队列,这个主队列是串行队列,每当调用一次 belowSerial() 或 belowParallel() 时,都会在主队列中创建一个子队列(串行队列或并行队列),当执行 request() 方法时,RequestQueue 会依次遍历主队列中的子队列,只有当当前子队列中的任务 完成后,才会继续执行下一个子队列。

如果想实现特殊的队列,只需要实现 TaskQueue 接口,然后编写自己的队列逻辑即可。


setSuccessListener(listener: RequestSuccessListener<any>): RequestQueue

Request 成功监听,每成功一个 Request,次方法都会被执行一次

setFailListener(listener: RequestFailListener<any>): RequestQueue

Request 失败监听,只要有一个 Request 失败,此方法就会被回调,同时会停止当前的 RequestQueue

setCompleteListener(listener: RequestCompleteListener): RequestQueue

当 RequestQueue 中的所有任务执行完成后,此方法会被回调

0.0.1

3 years ago