变量上的JavaScript事件循环操作是否阻塞?

变量上的JavaScript事件循环操作是否阻塞?,javascript,node.js,asynchronous,concurrency,event-loop,Javascript,Node.js,Asynchronous,Concurrency,Event Loop,在JavaScript的非阻塞事件循环中,读取并更改变量是否安全?如果两个进程几乎同时更改一个变量,会发生什么情况 示例A: 过程1:获取变量A(它是100) 过程2:获取变量A(它是100) 流程1:添加1(它是101) 流程2:添加1(它是101) 结果:变量A是101而不是102 这是一个简化的例子,有一条快速路线。假设路由每秒调用1000次: let counter = 0; const getCounter = () => { return counter; }; c

在JavaScript的非阻塞事件循环中,读取并更改变量是否安全?如果两个进程几乎同时更改一个变量,会发生什么情况

示例A:

  • 过程1:获取变量A(它是100)
  • 过程2:获取变量A(它是100)
  • 流程1:添加1(它是101)
  • 流程2:添加1(它是101)
  • 结果:变量A是101而不是102
这是一个简化的例子,有一条快速路线。假设路由每秒调用1000次:

let counter = 0;

const getCounter = () => {
  return counter;
};

const setCounter = (newValue) => {
  counter = newValue;
};

app.get('/counter', (req, res) => {
  const currentValue = getCounter();
  const newValue     = currentValue + 1;
  setCounter(newValue);
});
示例B:

如果我们做一些更复杂的事情,比如
Array.findIndex()
,然后
Array.splice()
?可能是因为另一个事件进程已经更改了数组,所以找到的索引已经过时了吗

  • 处理findIndex(它是12000)
  • 过程B findIndex(它是34000)
  • 处理拼接索引12000
  • 过程B拼接索引34000
  • 结果:进程B删除了错误的索引,应改为删除了33999
示例C:

如果我们在示例B中添加一个异步操作呢

const veryLargeArray = [
  // ...
];

app.get('/remove', (req, res) => {
  const id = req.query.id;
  const i  = veryLargeArray.findIndex(val => val.id === id);

  someAsyncFunction().then(() => {
    veryLargeArray.splice(i, 1);
  });
});

这个问题很难找到合适的词语来描述。请随时更新标题。

根据@ThisIsNoZaku的链接,Javascript有一个“从运行到完成”的原则:

在处理任何其他消息之前,每个消息都会被完全处理

在对程序进行推理时,这提供了一些很好的属性,包括这样一个事实:每当函数运行时,它都不能被抢占,并且将在任何其他代码运行之前完全运行(并且可以修改函数操作的数据)。这与C不同,例如,如果一个函数在一个线程中运行,运行时系统可能会在任何时候停止该函数,以便在另一个线程中运行其他代码

这种模式的一个缺点是,如果消息需要太长时间才能完成,web应用程序将无法处理诸如单击或滚动之类的用户交互。浏览器通过“脚本运行时间过长”对话框缓解此问题。要遵循的一个良好实践是缩短消息处理时间,如果可能,将一条消息缩减为多条消息

进一步阅读:

因此,对于:

示例A:作为sitecounter,它可以很好地工作

示例B:这也很好,但是如果许多请求同时发生,那么最后提交的请求将等待相当长的一段时间

示例C:如果在
someAsyncFunction
完成之前发送了对
\remove
的另一个调用,则完全可能是数组无效。解决这个问题的方法是将索引查找移动到异步函数的
.then
子句中


在IMO中,以延迟为代价,这解决了许多潜在的痛苦并发问题。如果您必须优化请求的速度,那么我的建议是研究不同的体系结构(附加缓存等)。

Array.findIndex()
Array.map()
不是异步的,它们是同步的,但是
app.get()
是吗?您给出的示例都是使用内存数据的全局变量。你不应该在任何地方这样做。甚至不建议这样做。@xdeepakv这只是一个抽象问题的示例。本文档概述了Javascript并发模型:如果是这样,示例C不应该工作,是吗?我的错,是的,不能保证示例C可以工作。
const veryLargeArray = [
  // ...
];

app.get('/remove', (req, res) => {
  const id = req.query.id;
  const i  = veryLargeArray.findIndex(val => val.id === id);

  someAsyncFunction().then(() => {
    veryLargeArray.splice(i, 1);
  });
});