我正在尝试为某些事件处理程序创建一些装饰器:一些以处理程序A作为参数并返回函数B的简单函数,该函数执行一些操作,然后调用 A(...arguments)
。
我特别想构建一个装饰器,它应该在所有其他处理程序之后触发作为参数传递的处理程序。但是我注意到,如果事件是通过编程方式而不是手动方式触发的,则点击处理是不同的。
在<a href="some/path">bla</a>
标记的情况下特别明显,在[click
]事件上带有异步处理程序,该处理程序等待下一个线程完成其执行(即,在某个时刻具有< [await Promise.resolve()
)。例如,给出此代码
<a href="">click</a>
<script>
const a = document.querySelector('a')
a.addEventListener('click', fireLastDecorator(handler))
a.addEventListener('click', () => console.log('doing stuff...'))
setTimeout(click, 10000)
function handler(e) {
e.preventDefault()
console.log('done')
}
function fireLastDecorator(f) {
return async function() {
await Promise.resolve()
f.apply(this, arguments)
}
}
function click() {
a.click()
}
</script>
在10秒钟的超时期间,我可以随时在链接上单击任意按钮:该页面不会重新加载,因为即使存在,[
e.preventDefault()
await Promise.resolve()
语句也会阻止链接的加载。但是当setTimeout触发其click
函数(以编程方式)时,一旦程序等待await Promise.resolve()
这在输入类型提交时也很明显。
编辑
使用调试器,我注意到当手动而不是通过js触发单击时,脚本会遵循不同的路径:手动触发时,处理程序不会等待Promise解析,因此第二个处理程序在首先(就像Promise.resolve()被忽略)。通过js触发时,该处理程序会等待诺言,因此添加的第二个处理程序会在第一个处理程序之前触发。
我正在尝试为某些事件处理程序制作一些装饰器:一些简单的函数,这些函数以处理程序A作为参数,并返回执行某些操作然后调用A(... arguments)的函数B。那里...
setTimeout
情况下,您正在preventDefault()
回调中调用async
,该回调中包含await
-ed的Promise。当您等待Promise时,事件完成,此后将无法再通过preventDefault()
进行拦截。