#javascript #vue.js #axios
Вопрос:
Я использую vue-бесконечный загрузчик для отображения пользователей и загрузки их на прокрутку. Кроме того, у меня есть фильтр по имени.
Я следовал инструкциям, данным на https://peachscript.github.io/vue-infinite-loading/guide/use-with-filter-or-tabs.html
Вот HTML — код для фильтра:
<input v-model="name" type="text" class="form-control" placeholder="Search by name" @input="changeName">
И здесь соответствующие методы vue:
methods: {
infiniteHandler: function ($state) {
console.log(api this.parameter);
axios.get(api this.parameter, {params: {page: this.page}}).then((result) => {
if (result.data.meta.current_page <= result.data.meta.last_page) {
this.page = 1;
this.users.push(...result.data.data);
$state.loaded();
} else {
$state.complete();
}
});
},
changeName() {
this.parameter= '?name=' encodeURIComponent(this.name);
this.page = 1;
this.users = [];
this.infiniteId = 1;
},
Если я сейчас быстро введу «Макс» в качестве имени пользователя во введенном текстовом файле, то changeName
это будет выполнено 3 раза, один раз с M
, Ma
и Max
. Проблема в том, что вызовы выполняются параллельно, то есть пользователи, начинающиеся с Max
, также будут совпадать для начала с Ma
и M
. Таким образом, у меня внезапно появились дубликаты, а также пользователь с именами, которые начинаются не с Max
, а с Marjon
и т. Д.
На самом деле у меня changeName()
есть тайм-аут, чтобы предотвратить HTTP-вызов при каждом нажатии клавиши:
changeName() {
clearTimeout(this.timeout);
this.timeout = setTimeout(function() { ...}, 200);
},
Однако теоретическая проблема, описанная выше, все еще возможна здесь (если нажатия клавиш и вызовы HTTPS занимают более 200 мс).
Я хотел бы, чтобы затем, если пользователь вводит «Ma», а затем «Max», вызов axios, инициированный «Ma», был остановлен и немедленно был выполнен вызов «Max».
Ответ №1:
Чтобы отменить запросы axios, вы можете использовать canceltoken
Обратите внимание, как любой предыдущий запрос отменяется при вызове infiniteHandler
— и что маркер отмены удаляется по завершении запроса
Таким образом, никакого дополнительного кода, кроме нескольких строк здесь, не требуется
methods: {
infiniteHandler: function ($state) {
console.log(api this.parameter);
// _cancelSource is truthy if there's a request "in flight"
if (this._cancelSource) {
this._cancelSource.cancel('new search');
this._cancelSource = null;
}
// get a new canceToken
this._cancelSource = axios.CancelToken.source();
axios.get(api this.parameter, {
cancelToken: this._cancelSource.token
params: {page: this.page}
}).then((result) => {
// no need to cancel now
this._cancelSource = null;
if (result.data.meta.current_page <= result.data.meta.last_page) {
this.page = 1;
this.users.push(...result.data.data);
$state.loaded();
} else {
$state.complete();
}
});
},
В случае, если отмена не совсем сработает — вы можете связать обещания, возвращенные axios
Однако я не верю, что это потребуется
Все еще может быть полезно, если вы не хотите отменять предыдущий запрос (для какой-либо другой цели), удалив код cancelToken
methods: {
infiniteHandler: function ($state) {
console.log(api this.parameter);
// initialise the promise for first time
this._requestPromise = this._requestPromise || Promise.resolve();
// _cancelSource is truthy if there's a request "in flight"
if (this._cancelSource) {
this._cancelSource.cancel('new search');
this._cancelSource = null;
}
// get a new canceToken
this._cancelSource = axios.CancelToken.source();
// chain on to the previous request
// NOTE: cancelling the previous request will make it reject ...
// but that can be handled
this._requestPromise = this._requestPromise
// handle any cancelled previous request
// or previous request rejections
// we still want to do this one if the previous rejected
.catch(() => {})
.then(() => {
axios.get(api this.parameter, {
cancelToken: this._cancelSource.token
params: {page: this.page}
}).then((result) => {
// no need to cancel now
this._cancelSource = null;
if (result.data.meta.current_page <= result.data.meta.last_page) {
this.page = 1;
this.users.push(...result.data.data);
$state.loaded();
} else {
$state.complete();
}
});
});
},
Ответ №2:
Вы можете отменить запрос axios прямо перед тем, как другой начнет использовать функцию отмены axios
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get(api this.parameter, {
params: {page: this.page}},
cancelToken: source.token
).then((result) => {
if (result.data.meta.current_page <= result.data.meta.last_page) {
this.page = 1;
this.users.push(...result.data.data);
$state.loaded();
} else {
$state.complete();
}
});
(Код не проверен, но дает представление)