From 2d691b69cbb2d3e27be3698bf4a4188cf71ccb7e Mon Sep 17 00:00:00 2001 From: zjx0905 <954270063@qq.com> Date: Thu, 20 Apr 2023 21:49:26 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=B8=8B=E8=BD=BD=E8=BF=9B=E5=BA=A6/?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E8=BF=9B=E5=BA=A6=20=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/pages/basics/download.md | 10 +-- docs/pages/basics/upload.md | 6 +- docs/pages/guide/quick-start.md | 31 +++++++- scripts/test.utils.ts | 10 ++- src/adapter.ts | 6 +- src/core/Axios.ts | 120 +++++++++++++++++------------- src/core/request.ts | 9 +-- src/helpers/isTypes.ts | 7 -- src/index.ts | 6 +- test/axios.api.test.ts | 12 +-- test/axios.instance.test.ts | 16 +--- test/core/Axios.test.ts | 15 ++-- test/core/AxiosDomain.test.ts | 7 +- test/core/dispatchRequest.test.ts | 8 +- test/core/flattenHeaders.test.ts | 23 ++---- test/core/generateType.test.ts | 16 +--- test/core/request.test.ts | 12 +-- test/helpers/isTypes.test.ts | 20 ----- 18 files changed, 152 insertions(+), 182 deletions(-) diff --git a/docs/pages/basics/download.md b/docs/pages/basics/download.md index 831272c..18a809c 100644 --- a/docs/pages/basics/download.md +++ b/docs/pages/basics/download.md @@ -71,14 +71,14 @@ axios('https://api.com/test', { }, onDownloadProgress(event) { const { - // 下载进度 + // 下载进度百分比 progress, - // 已经下载的数据长度 - totalBytesSent, + // 已经下载的数据长度,单位 Bytes + totalBytesWritten, - // 预期需要下载的数据总长度 - totalBytesExpectedToSend, + // 预预期需要下载的数据总长度,单位 Bytes + totalBytesExpectedToWrite, } = event; }, }) diff --git a/docs/pages/basics/upload.md b/docs/pages/basics/upload.md index 529a406..caebc2a 100644 --- a/docs/pages/basics/upload.md +++ b/docs/pages/basics/upload.md @@ -101,13 +101,13 @@ axios('https://api.com/test', { }, onUploadProgress(event) { const { - // 上传进度 + // 上传进度百分比 progress, - // 已经上传的数据长度 + // 已经上传的数据长度,单位 Bytes totalBytesSent, - // 预期需要上传的数据总长度 + // 预期需要上传的数据总长度,单位 Bytes totalBytesExpectedToSend, } = event; }, diff --git a/docs/pages/guide/quick-start.md b/docs/pages/guide/quick-start.md index 7e8b012..ab21c4b 100644 --- a/docs/pages/guide/quick-start.md +++ b/docs/pages/guide/quick-start.md @@ -80,7 +80,6 @@ axios('test'); const { // 静态对象 // 注意:默认导出的 axios 在 CommonJS 里是以 default 属性的方式存在 - // import axios from 'axios-miniprogram' 等于 const axios = require('axios-miniprogram').default default: axios, // 取消令牌 @@ -125,6 +124,36 @@ const { :::: +不同的模块系统存在一些小差异,`esm` 会自动处理默认导入,但 `cjs` 不会处理默认导入。 + +```ts +// 默认导入,esm 和 cjs 这两种写法是等价关系 +import axios from 'axios-miniprogram'; +const axios = require('axios-miniprogram').default; + +// 别名导入,esm 和 cjs 这两种写法是等价关系 +import * as axios from 'axios-miniprogram'; +const axios = require('axios-miniprogram'); + +// 具名导入,esm 和 cjs 这两种写法是等价关系 +import { + default as axios, + CancelToken, + isCancel, + Axios, + isAxiosError, + createAdapter, +} from 'axios-miniprogram'; +const { + default: axios, + CancelToken, + isCancel, + Axios, + isAxiosError, + createAdapter, +} = require('axios-miniprogram'); +``` + ## 使用 ### `axios(url, config?)` diff --git a/scripts/test.utils.ts b/scripts/test.utils.ts index 510247e..abdf094 100644 --- a/scripts/test.utils.ts +++ b/scripts/test.utils.ts @@ -113,8 +113,14 @@ export function mockAdapterFail(options: MockAdapterOptions = {}) { return mockAdapterBase('fail', options); } -export const testEachMethods = test.each([ +export const methods = [ ...requestMethodNames, ...requestMethodWithParamsNames, ...requestMethodWithDataNames, -]); +]; + +export const testEachMethods = test.each(methods); + +export function eachMethods(cb: (k: (typeof methods)[number]) => void) { + methods.forEach(cb); +} diff --git a/src/adapter.ts b/src/adapter.ts index b654666..9f5db09 100644 --- a/src/adapter.ts +++ b/src/adapter.ts @@ -1,7 +1,7 @@ import { isFunction, isPlainObject } from './helpers/isTypes'; import { assert } from './helpers/error'; import { - AxiosProgressCallback, + AxiosProgressEvent, AxiosRequestFormData, AxiosRequestHeaders, } from './core/Axios'; @@ -229,8 +229,8 @@ export type AxiosAdapterPlatformTask = | void | { abort?(): void; - onProgressUpdate?(callback: AxiosProgressCallback): void; - offProgressUpdate?(callback: AxiosProgressCallback): void; + onProgressUpdate?(callback: (event: AxiosProgressEvent) => void): void; + offProgressUpdate?(callback: (event: AxiosProgressEvent) => void): void; }; /** diff --git a/src/core/Axios.ts b/src/core/Axios.ts index 6b1b99a..f5d3a5d 100644 --- a/src/core/Axios.ts +++ b/src/core/Axios.ts @@ -1,7 +1,7 @@ import { buildURL } from '../helpers/buildURL'; import { isAbsoluteURL } from '../helpers/isAbsoluteURL'; import { combineURL } from '../helpers/combineURL'; -import { isFunction, isPromise, isString } from '../helpers/isTypes'; +import { isString } from '../helpers/isTypes'; import { AxiosAdapter, AxiosAdapterRequestMethod, @@ -102,33 +102,55 @@ export type AxiosRequestData = export type AxiosResponseData = number | AxiosAdapterResponseData; /** - * 监听进度回调事件对象 + * 进度对象 */ -export interface AxiosProgressEvent { +export interface AxiosProgressEvent extends AnyObject { /** - * 下载进度 + * 上传进度百分比 */ progress: number; +} + +/** + * 下载进度对象 + */ +export interface AxiosDownloadProgressEvent extends AxiosProgressEvent { /** - * 已经下载的数据长度 + * 已经下载的数据长度,单位 Bytes + */ + totalBytesWritten: number; + /** + * 预预期需要下载的数据总长度,单位 Bytes + */ + totalBytesExpectedToWrite: number; +} + +/** + * 监听下载进度 + */ +export interface AxiosDownloadProgressCallback { + (event: AxiosDownloadProgressEvent): void; +} + +/** + * 上传进度对象 + */ +export interface AxiosUploadProgressEvent extends AxiosProgressEvent { + /** + * 已经上传的数据长度,单位 Bytes */ totalBytesSent: number; /** - * 预期需要下载的数据总长度 + * 预期需要上传的数据总长度,单位 Bytes */ totalBytesExpectedToSend: number; } /** - * 监听进度回调 + * 监听上传进度 */ -export interface AxiosProgressCallback { - ( - /** - * 事件对象 - */ - event: AxiosProgressEvent, - ): void; +export interface AxiosUploadProgressCallback { + (event: AxiosUploadProgressEvent): void; } /** @@ -197,15 +219,15 @@ export interface AxiosRequestConfig /** * 错误处理 */ - errorHandler?: (error: unknown) => Promise | void; - /** - * 监听上传进度 - */ - onUploadProgress?: AxiosProgressCallback; + errorHandler?: (error: unknown) => Promise; /** * 监听下载进度 */ - onDownloadProgress?: AxiosProgressCallback; + onDownloadProgress?: AxiosUploadProgressCallback; + /** + * 监听上传进度 + */ + onUploadProgress?: AxiosUploadProgressCallback; } /** @@ -321,40 +343,34 @@ export default class Axios extends AxiosDomain { }; #processRequest(config: AxiosRequestConfig) { - const chain: [ - Interceptor | Interceptor, - ] = [ - { - resolved: dispatchRequest, - }, - ]; + const requestHandler = { + resolved: dispatchRequest, + }; + const errorHandler = { + rejected: config.errorHandler, + }; + const chain: ( + | Partial> + | Partial> + )[] = []; - this.interceptors.request.forEach(chain.unshift.bind(chain)); - this.interceptors.response.forEach(chain.push.bind(chain)); - - let next = Promise.resolve(config); - for (const { resolved, rejected } of chain) { - next = next.then( - // @ts-ignore - resolved, - rejected, - ); - } - - // 错误处理 - next = next.catch((reason) => { - const { errorHandler } = config; - - if (isFunction(errorHandler)) { - const promise = errorHandler(reason); - if (isPromise(promise)) { - return promise.then(() => Promise.reject(reason)); - } - } - - return Promise.reject(reason); + this.interceptors.request.forEach((requestInterceptor) => { + chain.unshift(requestInterceptor); }); + chain.push(requestHandler); + this.interceptors.response.forEach((responseInterceptor) => { + chain.push(responseInterceptor); + }); + chain.push(errorHandler); - return next as Promise; + return chain.reduce( + (next, { resolved, rejected }) => + next.then( + // @ts-ignore + resolved, + rejected, + ), + Promise.resolve(config), + ) as Promise; } } diff --git a/src/core/request.ts b/src/core/request.ts index eb1a491..7b922f1 100644 --- a/src/core/request.ts +++ b/src/core/request.ts @@ -6,12 +6,7 @@ import { AxiosAdapterResponseError, AxiosAdapterPlatformTask, } from '../adapter'; -import { - AxiosProgressCallback, - AxiosRequestConfig, - AxiosResponse, - AxiosResponseError, -} from './Axios'; +import { AxiosRequestConfig, AxiosResponse, AxiosResponseError } from './Axios'; import { isCancelToken } from './cancel'; import { AxiosErrorResponse, createError } from './createError'; import { generateType } from './generateType'; @@ -103,7 +98,7 @@ export function request(config: AxiosRequestConfig) { function tryToggleProgressUpdate( adapterConfig: AxiosAdapterRequestConfig, - adapterProgress?: (callback: AxiosProgressCallback) => void, + adapterProgress?: (cb: (event: AnyObject) => void) => void, ) { const { onUploadProgress, onDownloadProgress } = adapterConfig; if (isFunction(adapterProgress)) { diff --git a/src/helpers/isTypes.ts b/src/helpers/isTypes.ts index 147052a..716da42 100644 --- a/src/helpers/isTypes.ts +++ b/src/helpers/isTypes.ts @@ -30,10 +30,3 @@ export function isDate(date: any): date is Date { export function isFunction(value: any): value is T { return typeof value === 'function'; } - -export function isPromise(value: any): value is Promise { - return ( - _toString.call(value) === '[object Promise]' || - (isPlainObject(value) && isFunction(value.then)) - ); -} diff --git a/src/index.ts b/src/index.ts index ca5dc2e..b89fd58 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,8 +9,10 @@ export type { AxiosResponse, AxiosResponseData, AxiosResponseError, - AxiosProgressEvent, - AxiosProgressCallback, + AxiosDownloadProgressEvent, + AxiosDownloadProgressCallback, + AxiosUploadProgressEvent, + AxiosUploadProgressCallback, } from './core/Axios'; export type { AxiosAdapter, diff --git a/test/axios.api.test.ts b/test/axios.api.test.ts index c43c1a8..80196e3 100644 --- a/test/axios.api.test.ts +++ b/test/axios.api.test.ts @@ -2,14 +2,10 @@ import { describe, test, expect } from 'vitest'; import Axios from '@/core/Axios'; import { CancelToken, isCancel } from '@/core/cancel'; import { isAxiosError } from '@/core/createError'; -import { - requestMethodNames, - requestMethodWithDataNames, - requestMethodWithParamsNames, -} from '@/core/AxiosDomain'; import { createAdapter } from '@/adapter'; import axios from '@/axios'; import defaults from '@/defaults'; +import { eachMethods } from 'scripts/test.utils'; describe('src/axios.ts', () => { test('应该有这些静态属性', () => { @@ -35,11 +31,7 @@ describe('src/axios.ts', () => { expect(instance.fork).toBeTypeOf('function'); expect(instance.request).toBeTypeOf('function'); - [ - ...requestMethodNames, - ...requestMethodWithParamsNames, - ...requestMethodWithDataNames, - ].forEach((k) => { + eachMethods((k) => { expect(instance[k]).toBeTypeOf('function'); }); }); diff --git a/test/axios.instance.test.ts b/test/axios.instance.test.ts index 2788cd4..ced089b 100644 --- a/test/axios.instance.test.ts +++ b/test/axios.instance.test.ts @@ -1,11 +1,7 @@ import { describe, test, expect } from 'vitest'; -import { - requestMethodNames, - requestMethodWithDataNames, - requestMethodWithParamsNames, -} from '@/core/AxiosDomain'; import axios from '@/axios'; import defaults from '@/defaults'; +import { testEachMethods } from 'scripts/test.utils'; describe('src/axios.ts', () => { test('应该有这些实例属性及方法', () => { @@ -14,13 +10,9 @@ describe('src/axios.ts', () => { expect(axios.getUri).toBeTypeOf('function'); expect(axios.fork).toBeTypeOf('function'); expect(axios.request).toBeTypeOf('function'); + }); - [ - ...requestMethodNames, - ...requestMethodWithParamsNames, - ...requestMethodWithDataNames, - ].forEach((k) => { - expect(axios[k]).toBeTypeOf('function'); - }); + testEachMethods('%s 应该是一个函数', (k) => { + expect(axios[k]).toBeTypeOf('function'); }); }); diff --git a/test/core/Axios.test.ts b/test/core/Axios.test.ts index 5b3faa8..d35175c 100644 --- a/test/core/Axios.test.ts +++ b/test/core/Axios.test.ts @@ -3,11 +3,12 @@ import { mockAdapter, mockAdapterError, mockAdapterFail, + testEachMethods, } from 'scripts/test.utils'; import AxiosDomain, { requestMethodNames, - requestMethodWithDataNames, requestMethodWithParamsNames, + requestMethodWithDataNames, } from '@/core/AxiosDomain'; import Axios from '@/core/Axios'; import axios from '@/axios'; @@ -34,14 +35,10 @@ describe('src/core/Axios.ts', () => { expect(axiosObj.request).toBeTypeOf('function'); expect(axiosObj.getUri).toBeTypeOf('function'); expect(axiosObj.fork).toBeTypeOf('function'); + }); - [ - ...requestMethodNames, - ...requestMethodWithParamsNames, - ...requestMethodWithDataNames, - ].forEach((k) => { - expect(axiosObj[k]).toBeTypeOf('function'); - }); + testEachMethods('%s 应该是一个函数', (k) => { + expect(axiosObj[k]).toBeTypeOf('function'); }); test('应该可以发送普通别名请求', () => { @@ -162,6 +159,7 @@ describe('src/core/Axios.ts', () => { url: 'test', errorHandler: async (err: unknown) => { e1(err); + return Promise.reject(err); }, }; const c2 = { @@ -169,6 +167,7 @@ describe('src/core/Axios.ts', () => { url: 'test', errorHandler: async (err: unknown) => { e2(err); + return Promise.reject(err); }, }; diff --git a/test/core/AxiosDomain.test.ts b/test/core/AxiosDomain.test.ts index 5696bbb..e8bee8e 100644 --- a/test/core/AxiosDomain.test.ts +++ b/test/core/AxiosDomain.test.ts @@ -6,6 +6,7 @@ import AxiosDomain, { requestMethodWithDataNames, } from '@/core/AxiosDomain'; import { AxiosResponse } from '@/core/Axios'; +import { eachMethods } from 'scripts/test.utils'; describe('src/core/AxiosDomain.ts', () => { test('应该有这些常量', () => { @@ -23,11 +24,7 @@ describe('src/core/AxiosDomain.ts', () => { expect(a.defaults).toEqual(c); expect(a.request).toBeTypeOf('function'); - [ - ...requestMethodNames, - ...requestMethodWithParamsNames, - ...requestMethodWithDataNames, - ].forEach((k) => { + eachMethods((k) => { expect(a[k]).toBeTypeOf('function'); }); }); diff --git a/test/core/dispatchRequest.test.ts b/test/core/dispatchRequest.test.ts index cd5b7d4..f218ade 100644 --- a/test/core/dispatchRequest.test.ts +++ b/test/core/dispatchRequest.test.ts @@ -1,5 +1,5 @@ import { describe, test, expect, vi } from 'vitest'; -import { asyncNext, mockAdapter } from 'scripts/test.utils'; +import { asyncNext, mockAdapter, testEachMethods } from 'scripts/test.utils'; import { dispatchRequest } from '@/core/dispatchRequest'; import { requestMethodNames, @@ -38,11 +38,7 @@ describe('src/core/dispatchRequest.ts', () => { ).not.toThrowError(); }); - test.each([ - ...requestMethodNames, - ...requestMethodWithDataNames, - ...requestMethodWithParamsNames, - ])('应该支持 %s 转全大写', (k) => { + testEachMethods('应该支持 %s 转全大写', (k) => { const c = { adapter: mockAdapter(), url: '/', diff --git a/test/core/flattenHeaders.test.ts b/test/core/flattenHeaders.test.ts index 3767a38..fcb7e0d 100644 --- a/test/core/flattenHeaders.test.ts +++ b/test/core/flattenHeaders.test.ts @@ -1,20 +1,11 @@ import { describe, test, expect } from 'vitest'; import { flattenHeaders } from '@/core/flattenHeaders'; -import { - requestMethodNames, - requestMethodWithDataNames, - requestMethodWithParamsNames, -} from '@/core/AxiosDomain'; +import { eachMethods, methods } from 'scripts/test.utils'; describe('src/core/flattenHeaders.ts', () => { - const keys = [ - ...requestMethodNames, - ...requestMethodWithParamsNames, - ...requestMethodWithDataNames, - ]; const baseHeaders = Object.fromEntries( - keys.map((k) => [k, { v1: `${k}1`, v2: `${k}2` }]), - ) as unknown as Record<(typeof keys)[number], AnyObject>; + methods.map((k) => [k, { v1: `${k}1`, v2: `${k}2` }]), + ) as unknown as Record<(typeof methods)[number], AnyObject>; test('应该支持空配置', () => { expect(flattenHeaders({})).toEqual({}); @@ -33,7 +24,7 @@ describe('src/core/flattenHeaders.ts', () => { const h2 = { v1: 1, v2: 2 }; const h3 = { ...h1, ...h2 }; - keys.forEach((a) => { + eachMethods((a) => { expect(flattenHeaders({ headers: h1, method: a })).toEqual(h1[a]); expect(flattenHeaders({ headers: h3, method: a })).toEqual(h2); }); @@ -48,14 +39,14 @@ describe('src/core/flattenHeaders.ts', () => { }; const h2 = { ...baseHeaders, ...h1 }; - keys.forEach((a) => { + eachMethods((a) => { expect(flattenHeaders({ headers: h1, method: a })).toEqual(h1.common); expect(flattenHeaders({ headers: h2, method: a })).toEqual(h2[a]); }); }); test.each( - keys.map((k) => [ + methods.map((k) => [ k, { common: { @@ -83,7 +74,7 @@ describe('src/core/flattenHeaders.ts', () => { v4: `${k}2`, }; - keys.forEach((a) => { + methods.forEach((a) => { expect(flattenHeaders({ headers: h, method: a })).toEqual( a !== k ? h1 : h2, ); diff --git a/test/core/generateType.test.ts b/test/core/generateType.test.ts index b15aa11..3d5a171 100644 --- a/test/core/generateType.test.ts +++ b/test/core/generateType.test.ts @@ -1,20 +1,10 @@ import { describe, test, expect } from 'vitest'; import { generateType } from '@/core/generateType'; -import { - requestMethodNames, - requestMethodWithDataNames, - requestMethodWithParamsNames, -} from '@/core/AxiosDomain'; +import { testEachMethods } from 'scripts/test.utils'; describe('src/core/generateType.ts', () => { - test('应该是一个 reuqest', () => { - for (const a of [ - ...requestMethodNames, - ...requestMethodWithParamsNames, - ...requestMethodWithDataNames, - ]) { - expect(generateType({ method: a })).toBe('request'); - } + testEachMethods('%s 应该是一个 reuqest', (k) => { + expect(generateType({ method: k })).toBe('request'); }); test('应该是一个 upload', () => { diff --git a/test/core/request.test.ts b/test/core/request.test.ts index 5a9640c..964cf18 100644 --- a/test/core/request.test.ts +++ b/test/core/request.test.ts @@ -1,17 +1,13 @@ import { describe, test, expect, vi } from 'vitest'; import { asyncTimeout, + eachMethods, mockAdapter, mockAdapterError, mockAdapterFail, testEachMethods, } from 'scripts/test.utils'; import { request } from '@/core/request'; -import { - requestMethodNames, - requestMethodWithDataNames, - requestMethodWithParamsNames, -} from '@/core/AxiosDomain'; import axios from '@/axios'; describe('src/core/request.ts', () => { @@ -200,11 +196,7 @@ describe('src/core/request.ts', () => { download: true, }); - [ - ...requestMethodNames, - ...requestMethodWithParamsNames, - ...requestMethodWithDataNames, - ].forEach((a) => { + eachMethods((a) => { request({ adapter: ({ type }) => { expect(type).toBe('request'); diff --git a/test/helpers/isTypes.test.ts b/test/helpers/isTypes.test.ts index 47342dc..f0c008d 100644 --- a/test/helpers/isTypes.test.ts +++ b/test/helpers/isTypes.test.ts @@ -7,7 +7,6 @@ import { isNull, isUndefined, isString, - isPromise, } from '@/helpers/isTypes'; describe('src/helpers/isTypes.ts', () => { @@ -54,23 +53,4 @@ describe('src/helpers/isTypes.ts', () => { expect(isString('')).toBeTruthy(); expect(isString(``)).toBeTruthy(); }); - - test('应该能判断是 Promise', () => { - expect(isPromise({})).toBeFalsy(); - expect(isPromise(Promise.resolve())).toBeTruthy(); - expect( - isPromise( - new Promise(function () { - return; - }), - ), - ).toBeTruthy(); - expect( - isPromise({ - then() { - return; - }, - }), - ).toBeTruthy(); - }); });