我正在 Zendesk 中构建一些功能,主要使用普通 JS(jQuery 也可用),并且我有一个按钮需要运行 API 调用以首先获取一些数据,然后才能完成其“真正”的工作。但异步数据是静态的——它永远不会根据用户或会话改变——所以我想在页面加载后立即预加载它,以节省以后的时间。但该按钮不应假定数据已加载,即使 90% 的情况下都已加载。我不想设置任何烦人的竞争条件。
过去,在类似的场景中,我通过默认禁用按钮并在异步数据加载后启用它来处理此问题。但我只是想知道是否有更好的模式。
当您使用现代 API(如
fetch
)异步加载数据时,您将使用 Promises 来管理异步性。
当您开始加载 Promise 时,将其存储在缓存中。
然后,当你想使用它时(例如,通过单击按钮),你只需
await
存储的 Promise 即可。如果预缓存已完成,它将已处于已解决状态。如果仍处于待处理状态,则操作将照常暂停,直到数据可用。
如果您使用的是较旧的 API(例如
XMLHttpRequest
),那么您可以手动将操作包装在 Promise 中。
const fetchData = () => {
return new Promise((resolve) => {
console.log("Simulating a long running data fetching operation");
let percent_done = 0;
(function fetchChunk() {
percent_done += 10;
console.log(`Loaded ${percent_done}%`);
if (percent_done >= 100) resolve("Here is your data");
else setTimeout(fetchChunk, 1000);
})();
});
};
const cache = fetchData();
const logData = async() => {
const clickTime = new Date();
const data = await cache;
const now = new Date();
console.log(`Data was "${data}" from click at ${clickTime.toLocaleTimeString()} (time now is ${now.toLocaleTimeString()})`);
};
document.querySelector("button").addEventListener('click', logData);
<button>Click me</button>