用 axios 搜索:新字符时取消之前的请求
Posted
技术标签:
【中文标题】用 axios 搜索:新字符时取消之前的请求【英文标题】:Search with axios: cancel previous request when new character 【发布时间】:2019-09-14 00:19:18 【问题描述】:我有一个搜索栏,每个字母都会更新结果,但是当用户快速输入 3 个字母时,之前的请求不会被取消,所以在他得到结果之前会有一个难看的延迟。
我已阅读此https://github.com/axios/axios#cancellation,也许我有点累,但我很难将它添加到我的项目中。它几乎起到了相反的效果,现在它需要永远。 您有什么建议或者您推荐一个好的教程以便我理解这一点吗?
<input v-model="query" type="text" class="form-control" placeholder="Runner name or description"
aria-label="Runner name or description"
aria-describedby="basic-addon2">
watch:
query:
handler: _.debounce(function ()
this.newSearch()
, 100)
,
methods:
searchItems()
let filters =
q: this.query
;
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.post('/Items/find', filters,
cancelToken: source.token
)
.catch(function(thrown)
if (axios.isCancel(thrown))
console.log('Request canceled', thrown.message);
)
.then(
response =>
if(this.Items!=null)
response.data.forEach(element =>
this.Items.push(element);
);
else
this.Items=response.data;
);
,
newSearch()
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
source.cancel('Cancel previous request');
this.countItems();
this.searchItems();
,
showMore()
this.startindex = this.startindex+this.nbrows;
this.searchItems();
,
countItems()
this.countItems=10;
let filters =
q: this.query
;
axios.post('/Items/count', filters).then(
response =>
this.countItems=response.data;
);
【问题讨论】:
你试过增加去抖吗? 【参考方案1】:问题是您在 newSearch 中创建了一个新的 canceltoken 并取消了它而不是原来的那个。 如果您将源代码保存在 Vue 组件上,您可以检查 newSearch(如果存在),然后再取消。 发布 Promise 完成后,您将再次删除源,以便在不需要(或可能)时无法取消。
searchItems()
let filters =
q: this.query
;
const CancelToken = axios.CancelToken;
this.searchItemsSource = CancelToken.source();
axios.post('/Items/find', filters,
cancelToken: this.searchItemsSource.token
)
.catch(function(thrown)
if (axios.isCancel(thrown))
console.log('Request canceled', thrown.message);
)
.then(
response =>
this.searchItemsSource = undefined;
if(this.Items!=null)
response.data.forEach(element =>
this.Items.push(element);
);
else
this.Items=response.data;
);
,
newSearch()
if (this.searchItemsSource)
this.searchItemsSource.cancel('Cancel previous request');
this.countItems();
this.searchItems();
,
关于此代码的附注;我实际上会将取消上一个请求移到 searchItems 方法中,因为同时有两个正在运行的调用是没有意义的。它看起来更像这样:
searchItems()
let filters =
q: this.query
;
if (this.searchItemsSource)
this.searchItemsSource.cancel('Cancel previous request');
const CancelToken = axios.CancelToken;
this.searchItemsSource = CancelToken.source();
axios.post('/Items/find', filters,
cancelToken: this.searchItemsSource.token
)
.catch(function(thrown)
if (axios.isCancel(thrown))
console.log('Request canceled', thrown.message);
)
.then(
response =>
this.searchItemsSource = undefined;
if(this.Items!=null)
response.data.forEach(element =>
this.Items.push(element);
);
else
this.Items=response.data;
);
,
newSearch()
this.countItems();
this.searchItems();
,
此时您可以问问自己是否需要 newSearch 方法,您可以删除它并将 countItems 调用也移到 searchItems 中。不过,这一切都取决于您的其余代码和功能。
【讨论】:
非常感谢这个完整的答案,事实上我也只是将 countitems 移到了 searchItems 中。更容易阅读:)【参考方案2】:我能够让它工作。诀窍是在启动 API 调用之前检查取消令牌是否存在。我不得不将 CancelToken
和 cancel
变量移到外面Vue
对象/组件..
此示例在 GitHub 上搜索存储库...
var cancel;
var CancelToken = axios.CancelToken;
new Vue(
el: "#app",
data:
query: "",
results: "",
isLoading: false
,
methods:
clear()
this.isLoading = false;
this.results = "";
this.query = "";
,
handleSearch: _.debounce(function()
this.preApiCall();
, 300),
preApiCall()
if (cancel != undefined)
cancel();
console.log("cancelled");
this.apiCall(this.query);
,
apiCall(query)
if (query !== "")
this.isLoading = true;
axios(
method: "get",
url: "https://api.github.com/search/repositories",
cancelToken: new CancelToken(function executor(c)
cancel = c;
),
params:
q: query
).then(res =>
this.results = JSON.parse(JSON.stringify(res.data.items));
this.isLoading = false;
).catch(err =>
this.results = err.message;
throw Error(err.message);
this.isLoading = false;
);
else
this.clear();
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<div id="app">
<input v-model="query" @keyup.stop="handleSearch" type="text" class="form-control" placeholder="Search">
<button @click.stop="clear">Clear</button>
<div v-if="isLoading">Loading...</div>
<ul v-if="results !== ''">
<li v-for="(r, index) in results" :key="index">
r.name
</li>
</ul>
</div>
[CodePen mirror]
已取消的请求:
【讨论】:
以上是关于用 axios 搜索:新字符时取消之前的请求的主要内容,如果未能解决你的问题,请参考以下文章