摘要:在本教程中,您将探索如何使用 JavaScript AbortController
来取消正在进行的网络请求。
JavaScript AbortController 简介
AbortController
是一个 Web API,允许您中止网络请求。它通过将一个 AbortSignal
与网络请求关联起来。该信号可用于与网络请求通信,以便在必要时中止它们。
以下是使用 AbortController
中止 fetch 请求的步骤
首先,使用 new
关键字创建一个 AbortController
对象
const controller = new AbortController();
Code language: JavaScript (javascript)
其次,获取 AbortController
对象的 signal
属性。signal
属性是 AbortSignal
对象的一个实例
const signal = controller.signal;
Code language: JavaScript (javascript)
该 signal
可以传递给 fetch 请求,使我们能够控制其行为。
第三,将 AbortSignal
对象传递给 fetch 方法
fetch(url, { signal });
Code language: JavaScript (javascript)
或者,您可以将 signal
传递给 Request
对象并在 fetch
方法中使用它
const request = new Request(url, { signal });
fetch(request);
Code language: JavaScript (javascript)
第四,如果需要,通过调用 AbortController
对象的 abort()
方法来中止 fetch 请求。
controller.abort();
Code language: JavaScript (javascript)
例如,您在 2 秒后使 fetch 超时
setTimeout(() => controller.abort(), 2000);
Code language: JavaScript (javascript)
如果您在 fetch 完成后调用 abort(),则没关系,fetch 将忽略它。
第五,当您调用 abort() 方法时,它会通知 abort 信号。您可以使用 signal 对象上的 addEventListener 监听 abort 事件
signal.addEventListener('abort', () => {
console.log(signal.aborted); // true
});
Code language: JavaScript (javascript)
最后,您可以对中止的 fetch 做出反应
fetch(url, { signal }).then(response => {
return response.json();
}).then(data => {
console.log(data);
}).catch(err => {
if (err.name === 'AbortError') {
console.log('Fetch aborted');
}
});
Code language: JavaScript (javascript)
请注意,AbortError
不是真正的错误,因此我们使用 if
语句专门处理 AbortError
。
JavaScript AbortController 示例
在实践中,您在处理用户交互时使用 AbortController
。例如,在搜索页面上,当用户搜索新搜索词时,您可以中止先前的请求。
我们将构建一个 在维基百科上搜索词条的应用程序,如果用户在上次搜索完成之前开始新的搜索,则会取消先前的搜索请求。
步骤 1. 创建一个新目录来存储项目文件。
mkdir wikipedia-search-abortable
Code language: JavaScript (javascript)
步骤 2. 在项目目录中创建以下目录和文件
wikipedia-search-abortable
├── css
| └── style.css
├── img
| ├── spinner.svg
| └── wikipedia-logo.png
├── index.html
└── js
└── app.js
Code language: JavaScript (javascript)
步骤 3. 在 index.html
文件中创建 HTML 结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wikipedia Search</title>
<script src="./js/app.js" defer></script>
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<header>
<img src="./img/wikipedia-logo.png" alt="wikipedia">
<h1>Wikipedia Search</h1>
<form id="search">
<input type="search" name="term" id="term" placeholder="Enter a search term...">
</form>
</header>
<main>
<div id="searchResult"></div>
<div id="loading"></div>
<div id="error"></div>
</main>
</body>
</html>
Code language: HTML, XML (xml)
步骤 4. 使用以下代码修改 app.js
文件
const form = document.querySelector('#search');
const termInput = document.querySelector('#term');
const error = document.querySelector('#error');
const loading = document.querySelector('#loading');
const resultsContainer = document.querySelector('#searchResult');
let controller = new AbortController();
const search = async (term) => {
// Abort the previous request
console.log('Abort the previous request');
controller.abort();
// Create a new controller for the new request
controller = new AbortController();
const signal = controller.signal;
const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srsearch=${term}`;
const response = await fetch(url, { signal });
const data = await response.json();
return data.query.search;
};
const resetSearchResult = () => {
error.innerHTML = '';
loading.innerHTML = '';
resultsContainer.innerHTML = '';
};
const handleSubmit = async (e) => {
e.preventDefault();
// reset search result
resetSearchResult();
// check if term is empty
const term = termInput.value;
if (term === '') return;
try {
// show the loading
loading.innerHTML = `<img src='./img/spinner.svg' alt='loading...'>`;
// make the search
const results = await search(term);
// show the search result
resultsContainer.innerHTML = renderSearchResult(results);
} catch (err) {
// show the error
error.innerHTML = `Something went wrong.`;
console.error(err);
} finally {
// hide the loading
loading.innerHTML = '';
}
};
const renderSearchResult = (results) => {
return results
.map(({ title, snippet, pageid }) => {
return `<article>
<a href="https://en.wikipedia.org/?curid=${pageid}">
<h2>${title}</h2>
</a>
<div class="summary">${snippet}...</div>
</article>`;
})
.join('');
};
form.addEventListener('submit', handleSubmit);
Code language: JavaScript (javascript)
它是如何工作的。
首先,使用 querySelector
方法选择 DOM 元素
const form = document.querySelector('#search');
const termInput = document.querySelector('#term');
const error = document.querySelector('#error');
const loading = document.querySelector('#loading');
const resultsContainer = document.querySelector('#searchResult');
Code language: JavaScript (javascript)
其次,创建一个 AbortController
来中止 fetch 请求
let controller = new AbortController();
Code language: JavaScript (javascript)
第三,定义一个搜索函数,该函数根据输入的搜索词调用维基百科 API
const search = async (term) => {
// Abort the previous request
console.log('Abort the previous request');
controller.abort();
// Create a new controller for the new request
controller = new AbortController();
const signal = controller.signal;
const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srsearch=${term}`;
const response = await fetch(url, { signal });
const data = await response.json();
return data.query.search;
};
Code language: JavaScript (javascript)
在 search()
函数中,如果用户开始新的搜索,我们将调用 AbortController
对象的 abort()
方法来取消先前的搜索请求
controller.abort();
Code language: JavaScript (javascript)
在发出新请求之前,我们创建一个新的 AbortController
对象,并将它的 AbortSignal
传递给 fetch()
方法
controller = new AbortController();
const signal = controller.signal;
const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srsearch=${term}`;
const response = await fetch(url, { signal });
Code language: JavaScript (javascript)
步骤 5. 定义一个函数来重置错误、加载和搜索结果
const resetSearchResult = () => {
error.innerHTML = '';
loading.innerHTML = '';
resultsContainer.innerHTML = '';
};
Code language: JavaScript (javascript)
步骤 6. 定义一个 handleSubmit()
函数,在提交表单时执行搜索
const handleSubmit = async (e) => {
e.preventDefault();
// reset search result
resetSearchResult();
// check if term is empty
const term = termInput.value;
if (term === '') return;
try {
// show the loading
loading.innerHTML = `<img src='./img/spinner.svg' alt='loading...'>`;
// make the search
const results = await search(term);
// show the search result
resultsContainer.innerHTML = renderSearchResult(results);
} catch (err) {
// show the error
error.innerHTML = `Something went wrong.`;
console.error(err);
} finally {
// hide the loading
loading.innerHTML = '';
}
};
Code language: JavaScript (javascript)
它是如何工作的。
首先,阻止表单提交到服务器
e.preventDefault();
Code language: JavaScript (javascript)
其次,调用 resetSearchResult
函数来重置搜索结果
resetSearchResult();
Code language: JavaScript (javascript)
第三,如果搜索词为空,则立即返回
const term = termInput.value;
if (term === '') return;
Code language: JavaScript (javascript)
第四,在发出搜索请求之前显示加载进度指示器
loading.innerHTML = `<img src='./img/spinner.svg' alt='loading...'>`;
Code language: JavaScript (javascript)
第五,发出搜索请求
const results = await search(term);
Code language: JavaScript (javascript)
第六,显示搜索结果
resultsContainer.innerHTML = renderSearchResult(results);
Code language: JavaScript (javascript)
第七,显示用户友好的用户消息,并在控制台中记录错误详细信息
} catch (err) {
// show the error
error.innerHTML = `Something went wrong.`;
console.error(err);
}
Code language: JavaScript (javascript)
第八,无论是否发生错误,都隐藏加载指示器
} finally {
// hide the loading
loading.innerHTML = '';
}
Code language: JavaScript (javascript)
第九,定义一个函数 renderSearchResult
来渲染搜索结果
const renderSearchResult = (results) => {
return results
.map(({ title, snippet, pageid }) => {
return `<article>
<a href="https://en.wikipedia.org/?curid=${pageid}">
<h2>${title}</h2>
</a>
<div class="summary">${snippet}...</div>
</article>`;
})
.join('');
};
Code language: JavaScript (javascript)
最后,将 handleSubmit
函数注册为表单的提交事件处理程序
form.addEventListener('submit', handleSubmit);
Code language: JavaScript (javascript)
下载项目源代码
总结
- 使用
AbortController
中止 Web 请求,以防止不必要的网络请求并有效地处理用户交互。