這一章節,主要是寫取消請求
目錄:
取消請求
有些場景下,我們希望能主動取消請求,比如常見的搜索框案例,在用戶輸入過程中,搜索框的內容也在不斷變化,正常情況每次變化都應該向服務器發送一次請求,但在當用用戶輸入過快的時候,我們不希望每次變化請求都發出去,通常一個解決方案是前端用 debounce 的方案,比如延時 200 ms 發送請求,這樣當用戶連續輸入的字符,只要輸入間隔小於 200 ms,前面輸入的字符都不會發請求。但是還有一種極端情況下,後端接口很慢,比如超過1s才能響應,這個時候即使多了 200ms 的debounce,但是在我慢慢輸入(每個輸入間隔超過200ms)的情況下,在前面的請求沒有響應前,也有可能發出多個請求,因爲接口的響應時長是不定的,如果先發出去的請求響應時比後出發的請求要久一些,後請求的響應先回來,現請求的響應後回來,就會出現起請求響應結果覆蓋後面請求的響應結果的情況,那麼就亂了。因此在這個情況下,我們除了做 debounce,還希望後面的請求發出去的時候,如果前面的請求還沒有響應,我們可以把前面的請求取消。
我修改了 axios.ts
文件
// ...
import CancelToken from './cancel/CancelToken';
import Cancel, { isCancel } from './cancel/Cancel';
// ...
axios.CancelToken = CancelToken;
axios.Cancel = Cancel;
axios.isCancel = isCancel;
// ...
增加了 cancel
目錄
添加了 cancel/CancelToken.ts
文件
import { CancelExecutor, CancelTokenSource, Canceler } from "../types"
import Cancel from './Cancel';
interface ResolvePromise{
(reason?:Cancel):void
}
export default class CancelToken{
promise:Promise<Cancel>
reason?:Cancel
constructor(executor:CancelExecutor){
let resolvePromise:ResolvePromise
this.promise = new Promise<Cancel>(resolve => {
resolvePromise = resolve;
})
executor(message=>{
if(this.reason) {
return;
}
this.reason = new Cancel(message);
resolvePromise(this.reason)
})
}
throwIfRequested() {
if(this.reason) {
throw this.reason;
}
}
static source():CancelTokenSource {
let cancel!: Canceler
const token = new CancelToken((c: Canceler) => {
cancel = c;
})
return {
cancel,
token,
}
}
}
這裏巧妙的使用了 Promise
,通過後面的 xhr.ts
文件中進行的 .then
來調用函數。
添加了 cancel/Cancel.ts
文件
export default class Cancel{
message?: string
constructor (message?:string) {
this.message = message;
}
}
export function isCancel(value: any):boolean{
return value instanceof Cancel
}
其中 Cancel
類是 CancelToken
的類類型
修改core/dispatchRequest.ts
文件
// ...
import { flattenHeaders } from '../helpers/header';
// ...
export default function dispatchRequst (config :AxiosRequestConfig) : AxiosPromise {
throwIfCancellationRequested(config); // 放在最前面
// ...
}
// ...
function throwIfCancellationRequested (config: AxiosRequestConfig) : void {
if(config.cancleToken) {
config.cancleToken.throwIfRequested();
}
}
修改 xhr.ts
文件
// ...
if(cancleToken) {
cancleToken.promise.then(reason => {
request.abort()
reject(reason)
})
}
request.send(data);
// ...
修改 types/index.ts
文件
export interface AxiosRequestConfig {
// ...
cancleToken?:CancelToken,
// ...
}
// ...
export interface CancelToken{
promise: Promise<Cancel>,
reason?: Cancel,
throwIfRequested():void,
}
export interface Canceler{
(message?:string):void,
}
export interface CancelExecutor{
(cancel: Canceler):void,
}
export interface CancelExecutor{
(cancel:Canceler):void
}
export interface CancelTokenSource{
token: CancelToken,
cancel: Canceler,
}
export interface CancelTokenStatic{
new(executor:CancelExecutor):CancelToken,
source():CancelTokenSource,
}
export interface Cancel{
message?:string,
}
export interface CancelStatic{
new(message?:string):Cancel,
}
就寫這麼多了!