提问人:Niklas Mohrin 提问时间:3/15/2022 更新时间:3/15/2022 访问量:212
在处理当前窗体上的所有事件后运行的排队函数
Enqueuing function to run after all events on current form are handled
问:
我有一个带有事件处理程序的表单,如果在 DOM 中找到某个状态,该处理程序会更新一个字段。表单提交后,需要更改 DOM,但事件处理程序仍应遵守旧状态。目前,我通过在同一窗体上使用事件处理程序来实现这一点,因为这会将函数排入队列以稍后运行 - 希望在处理事件之后。我的问题是:这种行为是否得到保证,如果没有,是否有一种规范支持的方式来实现这种行为?formdata
FormData
formdata
setTimeout(() => {/*...*/}, 0)
submit
formdata
在事件循环的规范中,选择下一步要执行的工作的第一步描述为:
让 taskQueue 成为事件循环的任务队列之一,以实现定义的方式选择 [...]
然后,稍后将运行此所选队列中最早的任务。这意味着,如果调度的函数与事件处理程序位于同一任务队列中,并且如果事件处理程序是在提交处理程序实际运行之前调度的,那么我肯定是安全的 - 但我找不到任何证据。从 formdata
事件的文档(“在构造表示表单数据的条目列表后触发”)以及处理程序在处理程序之后运行的事实来看,我什至会假设相反的情况是正确的 - 但这不是我在上述方法中观察到的。setTimeout
formdata
formdata
submit
答:
你的理解是非常正确的,你是对的,可能并不总是在“相关”事件之后触发:这些事件确实很有可能是从两个不同的任务触发的,它们不太可能使用计时器任务源,并且你正确地识别了使事件循环“可能”从其他任务源中选择任务的位。setTimeout(fn, 0)
但是,在这种情况下,您是安全的。
事件和事件是从同一个“任务”*触发的。submit
formdata
如果查看表单提交算法,可以看到 submit 事件是在步骤 6.5 中直接触发的,而不是像通常那样被包装在排队的任务中。
设 shouldContinue 是触发在表单中命名的事件的结果 [...]
submit
然后在同一算法中,没有任何并行或任何暗示异步性的东西,我们有步骤 8 说
让条目列表是使用表单、提交者和编码构建条目列表的结果。
在这个构建条目列表算法时,在第 7 步中,我们调用
触发以表单命名的事件 [...]
formdata
再一次,不允许任何异步性。
因此,我们可以确定这些事件将在两者之间没有任何其他内容(除了微任务)的情况下触发,并且来自事件的计时器回调将在回调后触发,即使是在同一帧中调度的两个回调(对于事件循环也是“同步的”)也无法在那里交错:submit
formdata
requestAnimationFrame
document.forms[0].addEventListener("submit", e => {
console.log("submit");
});
document.forms[0].addEventListener("formdata", e => {
console.log("formdata");
});
requestAnimationFrame(() => {
console.log("rAF 1");
document.forms[0].querySelector("button").click();
});
requestAnimationFrame(() => {
console.log("rAF 2");
});
<form target="target">
<input value="foo" name="bar">
<button>
submit
</button>
</form>
<iframe name="target"></iframe>
*从技术上讲,它甚至不需要来自任务本身,您可以很好地强制这些事件从微任务或调整大小事件回调等触发。
评论
dispatchEvent
dispatchEvent
评论