From a162d05e5f9ac3d954575e91977a026cc9e88b42 Mon Sep 17 00:00:00 2001 From: chenjsh Date: Fri, 22 May 2020 15:58:13 +0800 Subject: [PATCH 1/2] feat: add AbortController polyfill --- README.md | 2 +- README_zh-CN.md | 2 +- src/cancel/abortControllerCancel.js | 21 +++++++++++- src/index.js | 5 +-- test/cancel/abortControllerCancel.test.js | 41 +++++++++++++++++++++++ types/index.d.ts | 3 ++ 6 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 test/cancel/abortControllerCancel.test.js diff --git a/README.md b/README.md index 970f431..bf9805d 100644 --- a/README.md +++ b/README.md @@ -770,7 +770,7 @@ Request.get('/api/cancel', { cancel(); ``` -3. create AbortCOntroller cancel +3. create AbortController cancel ```javascript import Request, { AbortController } from 'umi-request'; diff --git a/README_zh-CN.md b/README_zh-CN.md index c06575a..8d8d9fa 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -770,7 +770,7 @@ Request.get('/api/cancel', { cancel(); ``` -3. 通过 AbortCOntroller 取消 +3. 通过 AbortController 取消 ```javascript import Request, { AbortController } from 'umi-request'; diff --git a/src/cancel/abortControllerCancel.js b/src/cancel/abortControllerCancel.js index 20ef316..3faf9f5 100644 --- a/src/cancel/abortControllerCancel.js +++ b/src/cancel/abortControllerCancel.js @@ -1,3 +1,22 @@ -import AbortController from 'abort-controller'; +import { AbortController as AcAbortController, AbortSignal as AcAbortSignal } from 'abort-controller'; + +let AbortController = undefined; +let AbortSignal = undefined; + +const g = + typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : typeof global !== 'undefined' + ? global + : /* otherwise */ undefined; + +if (g) { + AbortController = typeof g.AbortController !== 'undefined' ? g.AbortController : AcAbortController; + AbortSignal = typeof g.AbortSignal !== 'undefined' ? g.AbortSignal : AcAbortSignal; +} export default AbortController; + +export { AbortController, AbortSignal }; diff --git a/src/index.js b/src/index.js index a834cf5..79e9c1e 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,8 @@ import request, { extend, fetch } from './request'; import Onion from './onion'; import { RequestError, ResponseError } from './utils'; -import AbortController from './cancel/abortControllerCancel'; +import { AbortController, AbortSignal } from './cancel/abortControllerCancel'; + +export { extend, RequestError, ResponseError, Onion, fetch, AbortController, AbortSignal }; -export { extend, RequestError, ResponseError, Onion, fetch, AbortController }; export default request; diff --git a/test/cancel/abortControllerCancel.test.js b/test/cancel/abortControllerCancel.test.js new file mode 100644 index 0000000..5d6b97c --- /dev/null +++ b/test/cancel/abortControllerCancel.test.js @@ -0,0 +1,41 @@ +import createTestServer from 'create-test-server'; +import request, { AbortController } from '../../src/index'; + +const writeData = (data, res) => { + res.setHeader('access-control-allow-origin', '*'); + res.send(data); +}; + +describe('test abortController', () => { + let server; + + beforeAll(async () => { + server = await createTestServer(); + }); + + afterAll(() => { + server.close(); + }); + + const prefix = api => `${server.url}${api}`; + + jest.useFakeTimers(); + + it('test request abort', () => { + expect.assertions(2); + server.get('/test/abort1', (req, res) => { + setTimeout(() => { + writeData(req.query, res); + }, 2000); + }); + + const controller = new AbortController(); + const { signal } = controller; + setTimeout(() => { + controller.abort(); + }, 500); + expect(signal.aborted).toBe(false); + jest.runAllTimers(); + expect(signal.aborted).toBe(true); + }); +}); diff --git a/types/index.d.ts b/types/index.d.ts index 4fd08c5..df38df6 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -163,4 +163,7 @@ declare var request: RequestMethod; export declare var fetch: RequestMethod; +export declare var AbortController: any; +export declare var AbortSignal: any; + export default request; From 73180d530ced806c7dc0921a1cf8f9966c7855df Mon Sep 17 00:00:00 2001 From: chenjsh Date: Fri, 22 May 2020 16:57:00 +0800 Subject: [PATCH 2/2] doc: update cases; update types --- README.md | 49 +++++++++++++++++++++++++------------------- README_zh-CN.md | 53 +++++++++++++++++++++++++++++------------------- types/index.d.ts | 5 +++-- 3 files changed, 63 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index bf9805d..00bc687 100644 --- a/README.md +++ b/README.md @@ -720,6 +720,34 @@ clientB.interceptors.request.use( ## Cancel request +### Use AbortController + +Base on [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) that allows you to abort one or more Web requests as and when desired. + +```javascript +import Request, { AbortController } from 'umi-request'; + +const controller = new AbortController(); // create a controller +const { signal } = controller; // grab a reference to its associated AbortSignal object using the AbortController.signal property + +signal.addEventListener('abort', () => { + console.log('aborted!'); +}); + +Request('/api/response_after_1_sec', { + signal, // pass in the AbortSignal as an option inside the request's options object (see {signal}, below). This associates the signal and controller with the fetch request and allows us to abort it by calling AbortController.abort(), +}); + +// 取消请求 +setTimeout(() => { + controller.abort(); // Aborts a DOM request before it has completed. This is able to abort fetch requests, consumption of any response Body, and streams. +}, 100); +``` + +### Use Cancel Token + +> Cancel Token still work, but we don’t recommend using them in the new code. + 1. You can cancel a request using a cancel token. ```javascript @@ -770,27 +798,6 @@ Request.get('/api/cancel', { cancel(); ``` -3. create AbortController cancel - -```javascript -import Request, { AbortController } from 'umi-request'; - -const controller = new AbortController(); -const { signal } = controller; - -signal.addEventListener('abort', () => { - console.log('aborted!'); -}); - -Request('http://127.0.0.1:3009/', { - signal, -}); -// 取消请求 -setTimeout(() => { - controller.abort(); -}, 1000); -``` - ## Cases ### How to get Response Headers diff --git a/README_zh-CN.md b/README_zh-CN.md index 8d8d9fa..91d6807 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -715,11 +715,41 @@ clientB.interceptors.request.use( ); ``` -## 取消请求 +## 中止请求 + +### 通过 AbortController 来中止请求 + +基于 [AbortController](https://developer.mozilla.org/zh-CN/docs/Web/API/FetchController) 方案来中止一个或多个DOM请求 + +```javascript +import Request, { AbortController } from 'umi-request'; + +const controller = new AbortController(); // 创建一个控制器 +const { signal } = controller; // 返回一个 AbortSignal 对象实例,它可以用来 with/abort 一个 DOM 请求。 + +signal.addEventListener('abort', () => { + console.log('aborted!'); +}); + +Request('/api/response_after_1_sec', { + signal, // 这将信号和控制器与获取请求相关联然后允许我们通过调用 AbortController.abort() 中止请求 +}); + +// 取消请求 +setTimeout(() => { + controller.abort(); // 中止一个尚未完成的DOM请求。这能够中止 fetch 请求,任何响应Body的消费者和流。 +}, 100); +``` + +### 使用cancel token 方案来中止请求 + +> Cancel Token 将逐步退出历史舞台,推荐使用 AbortController 来实现请求中止。 + 你可以通过 **cancel token** 来取消一个请求 -> cancel token API 是基于已被撤销的 [cancelable-promises 方案](https://github.com/tc39/proposal-cancelable-promises) +> cancel token API 是基于已被撤销的 [cancelable-promises 方案](https://github.com/tc39/proposal-cancelable-promises); + 1. 你可以通过 **CancelToken.source** 来创建一个 cancel token,如下所示: @@ -770,26 +800,7 @@ Request.get('/api/cancel', { cancel(); ``` -3. 通过 AbortController 取消 - -```javascript -import Request, { AbortController } from 'umi-request'; - -const controller = new AbortController(); -const { signal } = controller; -signal.addEventListener('abort', () => { - console.log('aborted!'); -}); - -Request('http://127.0.0.1:3009/', { - signal, -}); -// 取消请求 -setTimeout(() => { - controller.abort(); -}, 1000); -``` ## 案例 diff --git a/types/index.d.ts b/types/index.d.ts index df38df6..8947aa6 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -43,6 +43,7 @@ export interface RequestOptionsInit extends RequestInit { getResponse?: boolean; validateCache?: (url: string, options: RequestOptionsInit) => boolean; __umiRequestCoreType__?: string; + [key: string]: any; } export interface RequestOptionsWithoutResponse extends RequestOptionsInit { @@ -163,7 +164,7 @@ declare var request: RequestMethod; export declare var fetch: RequestMethod; -export declare var AbortController: any; -export declare var AbortSignal: any; +export declare var AbortController: { prototype: AbortController; new (): AbortController }; +export declare var AbortSignal: { prototype: AbortSignal; new (): AbortSignal }; export default request;