在事件处理程序中读写全局变量:并发何时成为问题?

Reading and writing global variables in event handlers: when is concurrency an issue ?

我是 Node.JS 的新手,我开始阅读有关 Node.js 事件处理和并发的几个主题。

下面的代码位触发事件 1000 次,这是通过递增全局变量来处理的。代码的第一位成功计数到 1000,但第二位甚至没有增加到 2。是否有任何我没有得到的原子性?

我仍然想知道为什么下面的代码给出了连贯的输出(它成功地计数到 1000,没有任何并发​​:

// Import events module
var events = require('events');

// Event emitter
var eventEmitter = new events.EventEmitter();

var max = 1000;

var count = 0;

eventEmitter.on('event', () => {
    let time = Math.trunc(Math.random() * 1000) +1;
    setTimeout(() => {  
        var c = count;
        c++;
        count = c;
        console.log(c);  
    }, time);
});

// Fire
for (let i = 0; i < max; i++) {
    eventEmitter.emit('event');
}

console.log('Program Ended.');

有没有我不明白的原子性?

但是当我移动 var 创建和赋值时,输出完全不同(最终结果是 1)。

// Import events module
var events = require('events');

// Event emitter
var eventEmitter = new events.EventEmitter();

var max = 1000;

var count = 0;

eventEmitter.on('event', () => {
    let time = Math.trunc(Math.random() * 1000) +1;
    var c = count;
    setTimeout(() => {  

        c++;
        count = c;
        console.log(c);  
    }, time);
});

// Fire
for (let i = 0; i < max; i++) {
    eventEmitter.emit('event');
}

console.log('Program Ended.');

有什么建议吗?任何阅读?

祝你有愉快的一天!

事件发射器最初在代码启动时一次性发出所有事件。所以 on 'event' 在启动程序后立即被触发。所有超时回调 在所有事件处理程序注册完成后调用。在你的 on event 回调中放置一个 console.log(而不是在 settimeout 回调中)并查看输出。

在第二个代码片段中,所有 settimeout 回调都捕获 count = 0 因为

var c = count;

settimeout 回调之外,因此回调将其递增到 1。

但在第一个代码片段中,计数是在回调中读取的

var c = count; 

所以每个回调都有更新的值。

来自Bergi提供的外部资源:

All Javascript event handler scripts are handled from one master event queue. This means that event handlers run one at a time and one runs until completion before the next one that's ready to go starts running. As such, there are no race conditions in Javascript. Any individual thread of execution in javascript will run to completion before the next one starts.

来自 this.

并且:

One event will run to completion before the next event is triggered. So, if a second click occurs while the first is still processing, the second click will be queued and will not run until the code processing the first one is done.

来自