如何让JavaScript等待特定事件发生?

问题描述 投票:0回答:6

我正在编写一个具有以下结构的网页:

  1. 一个部分(表 A)依赖于另一部分(表 B);
  2. 另一部分(表 B)包含每次更新时都需要重新计算的元素。计算由外部工具处理,完成后会引发一个事件。

为了保证正确性,只有在另一个表完全更新(即完成计算)后才需要更新该表。但是,我不知道如何有效地实现这一点,而且我在 JavaScript 中找不到任何

wait
工具。

目前我正在使用以下方法:

  1. 声明一个全局变量
    updated
    并使其成为
    false
    ;
  2. 第一个表收到输入后,我创建一个空的
    while
    循环,直到
    updated
    true
    ;
  3. 添加监听器,计算完成并收到事件后,将
    updated
    设置为
    true

这对我来说似乎不直观,但我想不出任何其他方法。有什么好的方法可以做到吗?

感谢您的任何意见!

javascript events web-applications wait
6个回答
27
投票

在 2022 年,拥有一个触发 Promise 的事件监听器(可以在 Promise 链或异步/等待代码中使用)会很有用。一种干净的制作方法:

function getPromiseFromEvent(item, event) {
  return new Promise((resolve) => {
    const listener = () => {
      item.removeEventListener(event, listener);
      resolve();
    }
    item.addEventListener(event, listener);
  })
}

async function waitForButtonClick() {
  const div = document.querySelector("div")
  const button = document.querySelector("button")
  div.innerText = "Waiting for you to press the button"
  await getPromiseFromEvent(button, "click")
  div.innerText = "The button was pressed!"
}
waitForButtonClick()
<button>ClickMe</button>
<div></div>


14
投票

添加一个监听器,一旦计算完成并收到事件,将更新设置为true。

不要将

updated
设置为 true,然后等待
updated
为 true - 只需在侦听器中执行您想做的任何操作即可。

myEventBus.addListener(function () {
    // do whatever
    updateTable();
    alert('table updated!');
});

8
投票

做空的 while 循环是一个坏主意。您不仅会消耗 CPU 周期,而且 Javacript 是单线程的,因此您将永远循环,而不给任何人更改变量的机会。

您可以做的是重写其他人依赖它的表以“触发事件本身”。有很多方法可以做到这一点,但基本上你只是希望它调用“继续”函数而不是盲目返回。这个函数可以是预定义的,或者你可以将它作为参数传递到某个地方。

//this is just illustrative
//Your actual code will be probably very different from this.

function update_part(){
    //do something
    signal_finished_part()
}

var parts_done = 0;
function signal_finished_part(){
    parts_done ++;
    if(parts_done >= 5){
        signal_all_parts_done();
    }
}

function signal_all_parts_done()
{
    //do something to table A
}

1
投票

您可以为触发更新的任何内容编写回调函数。为了避免混乱的回调,您也可以使用 Promise,并根据更新操作中检索到的数据更新表的部分内容。接受建议。


0
投票

我不得不重构一个充满 setTimeout() 的 JS 应用程序来处理事件同步(OMG)...

所以我花了一些时间创建一个小型事件内核作为起点。

您可以定义监听器等待特定事件范围内的其他监听器。

因此,您不是调用函数,而是触发事件。

每个工具/组件都可以按照正确的顺序做出相应的反应(因为你明确地说模块 B 需要 A)。事件对象沿着链传递,并且可以保存上下文(也称为您需要共享的数据)。

OC 在底层使用 Promise。

这是一些虚拟代码

qk.addEventListener('my_event', (e) => {
    // something
    notNeeded();
});

// your module foo does some init stuff
qk.addEventListener('my_event', async (e) => {
    // something async
    e.context.needed = await needed();
}, 'foo');

// somewhere else in your app your module bar is waiting after foo to set a specific context
qk.addEventListener('my_event', (e) => {
    // something after the async callback
    needing(e.context.needed);
}, 'bar', 'foo');

// call everything
qk.dispatchEvent(new QKE('my_event')).then(() => {
    // event my_event fully dispatched
    happyEnd();
});
// or await qk.dispatchEvent(new QKE('my_event'));

更多信息这里


0
投票

单行代码,

await
是元素上的事件:

await new Promise(r => el.addEventListener("click", r, {once:true}));
// `el` was clicked, now do stuff

或者如果您想等待多个事件中的任何一个发生:

await new Promise(r => ["mouseenter", "mousemove"].forEach(n => el.addEventListener(n, r, {once:true})));
// at least one of the events happened on `el`, now do stuff

只需更改事件名称以适合您的用例,然后更改

el
以引用您的元素。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.