等待并停止执行代码,直到事件处理程序触发

Wait and stop executing code till an event handler fires

我有启动一系列我可能不会更改的功能的代码:

doFirstThing();
doSecondThing();
doThirdThing();
// more functions...

每个函数都会创建一个事件处理程序。我想让函数做的是等到事件处理程序触发,然后才 return 并让下一个函数执行。我不能让第一个函数的事件监听器自己执行doSecondThing()(第二个执行第三个等等),因为每次执行的函数的顺序和数量都不一样。

我能想到的唯一解决方案是事件侦听器将 eventFired 之类的布尔值更改为 true,而函数中有一个无限的 while 循环检查并等待布尔值变为 true。

例如,假设有一个函数newText(str)改变按钮的文本,然后等待按钮被点击。完成后,函数最终 returns。以未知值执行此函数未知次数的代码是自动生成的,并且每次都不同,例如:

newText('Fizz');
newText('Buzz');
// some random code
newText('Foo');
// more code
newText('Bar');

所以预期的行为是有一个带有文本 "Fizz" 的按钮。单击后,文本将变为 "Buzz",依此类推,直到单击 "Bar"。四个函数调用之间可能还有一些其他代码,所以我认为不可能只让第一个函数创建一个事件处理程序,该事件处理程序在触发时调用下一个等等。

我相信这会占用大量资源,我可以使用 setTimeout() 每秒检查几次,但我觉得有更好、更干净、更有效的方法来做到这一点我找不到。或者这是解决此类问题的唯一且最好的方法?

您需要等待按钮被点击。为此,您需要将点击事件转换为 promise,当用户点击按钮时解析:

const once = (selector, event) => new Promise( res => document.querySelector(selector).addEventListener(event, res));

const setText = (selector, text) => document.querySelector(selector).textContent = text;

现在很容易做你想做的事了:

(async function(){
  setText("#btn", "click me");
  await once("#btn", "click");
  setText("#btn", "again please");
  await once("#btn", "click");
  setText("#btn", "done!");
})();

听起来您需要发送自定义事件。您可以通过触发将执行特定于该事件的代码的自定义事件来控制操作顺序。在下面的示例中,创建了 "Option" 个事件。给定您的场景,当单击按钮时,可以使用逻辑来确定下一步要做什么(选择哪个选项)。一旦决定,只需发送自定义事件。如果不触发下一个事件,则不会发生任何事情。

本质上,该操作绑定到自定义事件。事件的调度顺序决定了代码的执行顺序。

下面的示例代码(无法演示,因为 on-line 工具不支持自定义事件):

//Starting button
var buttonLabel = 'Fizz';
var currentOption = '';
// options represent the various "next steps" to take
var options = ['option1','option2','option3','option4','option5',];
var events = [];
options.forEach(o=>{
   var event = document.createEvent(o);
   events.push(event);
});
console.log(events);

function newText(){
  document.querySelector('button').textContent = buttonLabel;
}

function buttonClick(){
  switch (buttonLabel){
    case 'Fizz' :
      buttonLabel = 'Buzz';
      break;
    case 'Buzz' :
      buttonLabel = 'Foo';
      break;
    case 'Foo' :
      buttonLabel = 'Bar';
      break;
    case 'Bar' :
      buttonLabel = 'FooBar';
      break;
    case 'FooBar' :
      buttonLabel = 'Fizz';
      break;
    default :
      buttonLabel = 'What?';
      break;
  }
  currentOption = options[Math.random(0, options.length)];
  document.dispatchEvent(Math.random(0, options.length));
}
// Capture the button click...
document.querySelector('button').addEventListener('click', buttonClick);
// This sets up the activities (randomized here but just for demo)
document.addEventListener('option1', ()=>{
   alert('Option 1: \n running newText()...')

   newText();
});
document.addEventListener('option2', ()=>{
   alert('Option 2: \n doing something else...')
});

document.addEventListener('option3', ()=>{
   alert('Option 3: \n running newText()...')
   newText();
});

document.addEventListener('option4', ()=>{
   alert('Option 4: \n doing something else...')
});

document.addEventListener('option5', ()=>{
   alert('Option 5: \n running newText()...')
   newText();
});