如何在 fetch() 实际获取文件之前暂停 javascript 代码执行
Posted
技术标签:
【中文标题】如何在 fetch() 实际获取文件之前暂停 javascript 代码执行【英文标题】:How to pause javascript code execution until fetch() actually gets the file 【发布时间】:2021-08-17 06:34:24 【问题描述】:假设页面上的标准进程以这样的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 实现吗?
EDIT1:进一步说明
请记住,不确定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()
继续运行,以防没有可取的操作。
【问题讨论】:
我知道我们可以使用 setInterval 每 100 毫秒检查一次以查看 fetch 是否有结果,然后才触发 doTheseFirst() 和最后 clearInterval。但事实并非如此。 【参考方案1】:您可以执行以下操作
你定义了一些 html 来显示你的内容并隐藏它直到你的内容真正可用
你定义了一个按钮来再次隐藏这个元素
next
事件处理程序只是用来调用 Promise 解析回调,该回调将在需要时定义
当您的文本可用时,可将其添加到您的显示器并创建等待 new Promise
,单击下一步按钮即可解决此问题
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>
【讨论】:
这是否会暂停 setTimeouts 和 setIntervals 的所有滴答声,直到用户单击“确定”?因为警报框可以做到这一点。 不,这不会暂停任何超时。唯一会做的是,只有在通过单击按钮实现承诺后才会隐藏文本区域。 如果您在fetch
和window.load
之间存在竞争条件,则说明您的应用程序存在设计问题。如果您有彼此独立启动的任务,则它们不应依赖于彼此的结果。如果其中一项任务需要其他结果,则只能在另一项任务完成后启动。但是从你对问题的描述,没人能看出,你真正需要的是什么……
如果有另一种方法来控制事物的运行方式,我们就不必将其称为设计问题。如果没有任何东西可以做警报框可以做的事情,那么我当然必须改变代码的结构。
@TheLinguist 如果您根据您使用的语言规范正确地操作,您可以完美地控制事情的运行方式。顺便说一句,使用 alert
等待其他一些 JS 函数完成是行不通的。因为 JS 是单线程的。因此,在显示警报时,不会执行任何其他语句。【参考方案2】:
您可以将fetch
收到的文本文件的内容显示在漂亮的<div>
或提取中的任何元素中,然后退出函数。
您将EventListener
添加到一个按钮,当用户单击该按钮时,您可以移动到下一个操作。
【讨论】:
这很明显,但这不是对所问问题的回答。以上是关于如何在 fetch() 实际获取文件之前暂停 javascript 代码执行的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript 中的 Promises/Fetch:如何从文本文件中提取文本
如何从 fetch javascript 请求的响应中获取数据