只让最后一个 API 调用通过
IT技术
javascript
reactjs
api
axios
2021-04-16 10:15:04
2个回答
当您对用户输入进行异步调用时,异步结果解析的顺序可能不是用户提供输入的顺序(因此不是去抖动问题)。当用户输入时,s
您使用 进行异步调用s
,然后用户输入e
并使用 进行异步调用se
。现在有 2 个未解决的异步调用,s
一个与se
.
假设s
调用需要一秒钟,se
调用需要 10 毫秒,然后se
首先解析并且 UI 设置为 result ofse
但之后s
解析并且 UI 设置为 result of s
。您现在有一个不一致的用户界面。
解决此问题的一种方法是使用 debounce 并希望您永远不会收到持续时间超过 debounce 时间的异步调用,但不能保证。另一种方法是取消较旧的请求,但实现起来太麻烦,而且并非所有浏览器都支持。我在下面展示的方式只是在提出新请求时拒绝异步Promise。因此,当用户键入s
和e
请求s
并se
发出但在s
解决后将se
被拒绝,因为它已被更新的请求替换。
const REPLACED = 'REPLACED';
const last = (fn) => {
const current = { value: {} };
return (...args) => {
const now = {};
current.value = now;
return Promise.resolve(args)
.then((args) => fn(...args))
.then((resolve) =>
current.value === now
? resolve
: Promise.reject(REPLACED)
);
};
};
const later = (value, time) =>
new Promise((resolve) =>
setTimeout(() => resolve(value), time)
);
const apiCall = (value) =>
//slower when value length is 1
value.length === 1
? later(value, 1000) //takes a second
: later(value, 100); //takes 100ms
const working = last(apiCall);
const Api = ({ api, title }) => {
const [value, setValue] = React.useState('');
const [apiResult, setApiResult] = React.useState('');
React.useEffect(() => {
api(value).then((resolve) => {
console.log(title, 'resolved with', resolve);
setApiResult(resolve);
});
}, [api, title, value]);
return (
<div>
<h1>{title}</h1>
<h3>api result: {apiResult}</h3>
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
</div>
);
};
const App = () => (
<div>
<Api
api={apiCall}
title="Broken (type 2 characters fast)"
/>
<Api api={working} title="Working" />
</div>
);
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
使用 JavaScript 的 AbortController。它专门用于取消网络请求。
看看这个https://developer.mozilla.org/en-US/docs/Web/API/AbortController
其它你可能感兴趣的问题