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

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

示例 A:

  • 流程一:获取变量A(为100)

  • 过程2:获取变量A(为100)

  • 过程1:加1(就是101)

  • 过程2:加1(是101)

  • 结果:变量 A 是 101 而不是 102

这是一个简化的示例,具有 Express 路线。假设该路线每秒调用 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()thenArray.splice()呢?是不是因为另一个事件进程已经改变了数组,所以找到的索引已经过时了?

  • 进程 A findIndex(为 12000)

  • 进程 B findIndex(它是 34000)

  • 工艺A拼接索引12000

  • 工艺B拼接索引34000

  • 结果:进程 B 删除了错误的索引,应该删除 33999

const veryLargeArray = [

  // ...

];


app.get('/remove', (req, res) => {

  const id = req.query.id;

  const i  = veryLargeArray.findIndex(val => val.id === id);

  veryLargeArray.splice(i, 1);

});

示例 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);

  });

});

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


繁星coding
浏览 101回答 1
1回答

ABOUTYOU

根据@ThisIsNoZaku 的链接,Javascript 有一个“运行到完成”原则:在处理任何其他消息之前,每条消息都会被完全处理。这在推理您的程序时提供了一些很好的属性,包括这样一个事实:每当一个函数运行时,它不能被抢占并且将在任何其他代码运行之前完全运行(并且可以修改函数操作的数据)。这与 C 不同,例如,如果一个函数在一个线程中运行,它可能会在任何时候被运行时系统停止以在另一个线程中运行一些其他代码。此模型的一个缺点是,如果一条消息需要很长时间才能完成,Web 应用程序将无法处理用户交互,例如单击或滚动。浏览器通过“脚本运行时间过长”对话框来缓解这种情况。一个好的做法是缩短消息处理时间,如果可能的话,将一条消息缩减为多条消息。进一步阅读:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop因此对于:示例 A:这作为站点计数器非常有效。示例 B:这也可以正常工作,但是如果同时发生许多请求,那么最后提交的请求将等待相当长的时间。\remove示例 C:如果在完成之前发送另一个调用someAsyncFunction,那么您的数组完全有可能无效。解决这个问题的方法是将索引结果移动到.thenasync 函数的子句中。IMO,以延迟为代价,解决了许多潜在的痛苦并发问题。如果您必须优化请求的速度,那么我的建议是研究不同的架构(附加缓存等)。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript