如何使异步事件处理程序按一定顺序工作?

时间:2017-09-05 05:59:36

标签: javascript asynchronous javascript-events event-handling

我们说我有一个带有事件处理程序的按钮:

<button onclick="btnClicked()"> CLICK ME </button>

这是js文件:

var num = 0; // global variable

function btnClicked() { 
   num++;
   console.log(num);
}

我们说我在同一个按钮上点击了两次。我希望在控制台1和2中看到。

但是,这不是我必须得到的。每个按钮单击都会异步调用btnClicked函数,因此可能会出现第二个调用在第一个调用结束之前结束的情况。例如第一次调用调用btnClicked,传递行&#34; num ++&#34;然后持有(出于某种原因)。同时,第二次调用进入num = 1的函数,将其递增到2,在控制台中打印2,然后第一次调用继续执行num = 2,因此也打印2。

您是否知道有任何方法可以确保第二次调用仅在第一次调用结束后才会发生?

4 个答案:

答案 0 :(得分:1)

阅读完回复后,我了解到我描述的场景(控制台将两次打印“2”)是不可能的。

事件处理程序被添加到事件队列中。事件队列不是V8线程。因此,事件队列中的每个任务将同步执行,即仅在第一次调用结束后才开始第二次调用。

但是,如果功能是:

function btnClicked() { 
   num++;
   console.log(num);
   **AJAX call** 
}

然后执行顺序是: 打印:1 AJAX调用发送第一次调用 打印2 AJAX调用发送第二次调用

然后在这种情况下,两个AJAX调用都发生在不同的线程中,我们无法确定它们中的哪一个将首先结束。

答案 1 :(得分:0)

单击按钮,只需禁用按钮,在功能结束时启用按钮。你能试试吗?我认为这对你有用。

答案 2 :(得分:0)

虽然它可能无法直接解决您的问题,但建议您使用eventListener而不是onclick。

另外,要创建一个变量全局变量,您可以在没有&#39; var&#39; - 也许并不完全是你想要做的事情,例如&#39; num&#39;,但这会使它变得全球化(更多关于here)。

这会给你类似的东西:

<button id='click-me'> CLICK ME </button>

<script>
    num = 0; // global variable
    document.getElementById('click-me').addEventListener('click', function(){
        // function here
    });
</script>

答案 3 :(得分:0)

您只需要承诺解决订单问题。 每个事件都在各自进行。但是如果你有一个ajax请求,并且你需要在从服务器得到响应之后每个都发送一个ajax请求。然后通过按钮单击发送ajax请求(按特定顺序异步执行功能,每个按顺序执行)。所以这是一个带有伪执行函数的工作示例。

var num = 0;

var executing = new Promise(function(resolve, reject){
     resolve();
});

var btnHandle = function(){
  executing.then(createJobInstanse());
}

var createJobInstanse = function(){
 return function(){
      return new Promise(function(resolve, reject){
        // fake asynchronous operation from 10ms to 2000ms, with random execution time
        window.setTimeout(function(){
          console.log(num++);
          resolve();
        }, Math.floor(Math.random() * 2000) + 10);
      });
 };
}

  

var btn = document.querySelector("#btn");
btn.addEventListener("click",btnHandle);
<button id="btn" onclick="btnHandle">click</button>