項目中遇到的場景,
change
事件觸發模糊匹配時,短期內發送多個ajax
請求,最後一次返回的數據可能不是最後一次觸發change
時的請求,致使獲取數據不匹配ios
Axios
作數據請求,使用 cancel token
取消請求官方案例 github.com/axios/axiosgit
// using the CancelToken.source factory
const CancelToken = axios.CancelToken
const source = CancelToken.source()
// get
axios.get('/user/1', {
cancelToken: source.token
}).catch(function (thrown) {
if(axios.isCancel(thrown) {
console.log('Request canceled', thrown.message)
}) else {
// handle error
}
})
// post
axios.post('/user/1', {
name: ''
}, {
cancelToken: source.token
})
// cancel request 參數可選
source.cancel('取消上次請求')
複製代碼
// use executor function
const CancelToken = axios.CancelToken
let cancel
// get
axios.get('/user/1', {
cancelToken: new CancelToken(function executor(c) {
// executor 函數接收一個 cancel 函數做爲參數
cancel = c
})
})
// post
axios.post('/user/1', {
name: ''
}, {
cancelToken: new CancelToken(function executor(c) {
cancel = c
})
})
// cancel request
cancel()
複製代碼
個人
Vue
項目實例github
import axios from 'axios'
let cancel
let CancelToken
mounted() {
CancelToken = axios.CancelToken
}
// 屢次觸發fetchList請求 取消上次請求,觸發最新請求
async fetchList() {
if(cancel) {
cancel()
}
await axios.post('/user/list', {
query: ''
}, {
cancelToken: new CancelToken(function executor(c) {
cancel = c
})
})
}
複製代碼
原生的
XHR
對象是調用abort()
方法取消ajax
請求ajax
let xhr
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest()
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP')
}
xhr= new XMLHttpRequest()
xhr.open('GET', 'https://api')
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// success
} else {
// error
}
}
// 取消ajax請求 readyState = 0
xhr.abort()
複製代碼
Axios
源碼輕解析 CancelToken
axios/lib/cancel/CancelToken.js
axios
'use strict';
var Cancel = require('./Cancel');
function CancelToken(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
/** * 定義 resolvePromise * 新建promise實例 * 將 promise的resolve方法賦值給 resolvePromise 目的是爲了在promise對象外使用resolvePromise方法來改變對象狀態 */
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
/** * 將CancelToken實例賦值給token * 給executor傳入cancel方法,cancel可調用resolvePromise方法 */
var token = this;
executor(function cancel(message) {
if (token.reason) {
// 取消已響應 返回
return;
}
token.reason = new Cancel(message);
// 這裏執行的就是promise的resolve方法,改變狀態
resolvePromise(token.reason);
});
}
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
if (this.reason) {
throw this.reason;
}
};
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
// c 就是CancelToken中給executor傳入的cancel方法
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
module.exports = CancelToken;
複製代碼
執行
promise.resolve()
後如何取消ajax
請求api
CancelToken
添加到 axios
的CancelToken
屬性上// axios/lib/axios.js
axios.Cancel = require('./cancel/Cancel');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');
複製代碼
CancelToken
的 resolve
的方法觸發 promise.then
方法// axios/lib/adapters/xhr.js
// 建立XHR對象
var request = new XMLHttpRequest()
// 模擬當前ajax請求
request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true)
if (config.cancelToken) {
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
// 取消ajax請求
request.abort();
reject(cancel);
// Clean up request
request = null;
});
}
複製代碼