假设页面上的标准进程从这样的
window load
事件开始,
window.addEventListener("load",function(){ doTheseFirst(); }, { once: true });
function doTheseFirst()
{
setTimeout(function(){ andThenDoThese(); }, 5000);
// Maybe show some pictures and play some sounds for 5 seconds
}
function andThenDoThese()
{
// Show other pictures and play other sounds until user clicks OK
elementOnPageForOK.addEventListener("click", andThenDoTheseTooWhenUserClicksOK);
}
function andThenDoTheseTooWhenUserClicksOK()
{
// etc etc
// You get the idea
}
假设这段代码被一遍又一遍地使用。 但在某些情况下,用户必须在执行链开始运行之前看到通知。一个简单的解决方案是使用警报框,因为它会阻止/暂停代码执行。以下代码使
fetch()
从 txt
文件中获取内容后立即弹出警报框。请注意,fetch()
和 window load
是独立工作的。
fetch("somefolder/notification.txt").then(function(response){return response.text();}).then(function(contentOfTheTxtFile){ alert(contentOfTheTxtFile); });
这是有效的,因为当警报框关闭时,主代码会根据需要返回到正常流程。
但是我如何在不使用无法为其分配任何样式的原始警报框的情况下执行相同的操作? 我可以让代码执行在
fetch()
获取文件后立即暂停,然后在用户单击 OK 或 NEXT 按钮时立即取消暂停吗?
这可以通过 async/await 实现吗?
编辑1:进一步说明 请记住,
fetch()
或window load
是否会首先触发完成信号是不确定的。因为下载速度是完全不可预测的。
因此,如果我们将它们都设置为这样,我们不知道另一个需要多少毫秒才能赶上。
if(thisTimeItIsASpecialCase){
fetch("somefolder/notification.txt").then(function(response){return response.text();}).then(function(contentOfTheTxtFile){ /*What to do when the file is ready*/ });
}
window.addEventListener("load",function(){ doTheseFirst(); }, { once: true });
实现所需结果的简化方法:如果
doTheseFirst()
确实正在尝试获取文件,则将 fetch()
函数搁置并使其等待 fetch()
,并让它完成获取文件的任务。也让 doTheseFirst()
继续运行,以防没有需要执行的操作。
您可以执行以下操作
您定义一些要在其中显示内容并隐藏它的 html,直到您的内容真正可用
您定义一个按钮来再次隐藏该元素
next
事件处理程序只是用来调用 Promise 解析回调,该回调将在需要时定义
当您的文本可用时,将其添加到您的显示并创建等待
new Promise
,单击下一个按钮即可解决
承诺链中的下一个处理程序再次隐藏显示。
这段代码当然是非常基本和示意性的。对于实际使用,您可以将其封装在自己的类或模块中。如果您正在使用 React、Angular 等框架,那么有大量组件可供使用,它们恰好提供了此功能。例如作为模式对话框或其他任何形式。
var resolver = undefined;
function next() {
if (resolver) resolver.call();
}
function getText() {
fetch("https://baconipsum.com/api/?type=meat-and-filler¶s=3&format=text")
.then(response => response.text())
.then(text => {
document.getElementById("thetext").innerText = text;
document.getElementById("display").hidden = false;
return new Promise(resolve => {
resolver = resolve;
});
})
.then(() => {
document.getElementById("display").hidden = true;
resolver = undefined;
})
.catch(e => console.log(e));
}
<input type="button" onclick="getText()" value="Get Text">
<div id="display" hidden>
<div id="thetext"></div>
<input type="button" onclick="next()" value="OK">
</div>
fetch
是异步的,这基本上意味着
fetch('some_folder/some_file.xyz').then();
// Here at this point fetch has just started looking for the file and will be busy trying to get it
// And yet
console.log("This will immediately show regardless of how long it takes for fetch to complete");
有两种方法可以使其表现得像同步一样这意味着延迟所有后续任务直到获取完成。第一个是,
.then()
表示法时,通过 .finally()
喜欢
fetch('some_folder/some_file.txt').then(response => {return response.text();})
.then(text => { /*Do what you want with the contents of the txt file*/ })
.catch(error => { console.error('fetch could not get the file', error); })
.finally(whenFetchIsDone);
function whenFetchIsDone() {
console.log("This will show only after fetch completes either with or without success");
// Here we can call a function like goAheadAndPerformTheNextTaskInLine();
}
另一种方式是
await
函数内使用 async
和 try
catch
finally
块喜欢
async function fetchData() {
try {
const response = await fetch('some_folder/some_file.txt');
if (!response.ok) { throw new Error('fetch has failed'); }
const theText = await response.text();
// Do what you want with theText
} catch (error) {
console.error('could not read file', error);
} finally {
console.log("This will show only after fetch completes either with or without success");
// Here we can call a function like goAheadAndPerformTheNextTaskInLine();
}
}
fetchData();
请注意,通过使用任一方法都可以链接多个获取任务,以便在必要时一个接一个地下载文件。
您可以在漂亮的
fetch
或提取中的任何元素中显示通过 <div>
收到的文本文件的内容,然后退出该函数。
您将 EventListener
添加到按钮,当用户单击该按钮时,您可以移至下一个操作。