我知道JS是单线程的,技术上不可能有竞争条件,但由于异步和事件循环,应该会有一些不确定性.下面是一个过于简单化的例子:

class TestClass {
  // ...

  async a(returnsValue) {
     this.value = await returnsValue()
  }
  b() {
     this.value.mutatingMethod()
     return this.value
  }
  async c(val) {
     await this.a(val)
     // do more stuff
     await otherFunction(this.b())
  }
}

假设b()依赖于自对a()的调用以来未被更改的this.value,并且从程序中的多个不同位置快速连续多次调用c(val).这会不会造成一场数据竞赛,this.value会在呼叫a()b()之间发生变化?

作为参考,我已经先发制人地用mutex修复了我的问题,但我一直在质疑是否一开始就有问题.

推荐答案

是的,比赛条件在js中也可以并且确实会发生.仅仅因为它是单线程的,并不意味着竞争条件不会发生,尽管它更罕见.JavaScript确实是单线程的,但它也是异步的:指令的逻辑序列通常被划分为在不同时间执行的较小块.这使得交织成为可能,因此出现了竞争条件.


对于这个简单的例子,请考虑

var x = 1;

async function foo() {
    var y = x;
    await delay(100); // whatever async here
    x = y+1;
}

这是适应JS的异步世界的非原子增量的classic 例子.

现在比较以下"并行"执行:

await Promise.all([foo(), foo(), foo()]);
console.log(x);  // prints 2

用"顺序"的方式:

await foo();
await foo();
await foo();
console.log(x);  // prints 4

请注意,结果是不同的,即foo()不是"异步安全的".


即使在js中,有时也必须使用"异步互斥锁".您的例子可能就是其中一种情况,这取决于两者之间发生的情况,例如,如果发生某个异步调用.在do more stuff中没有异步调用,看起来就像是在单个代码块中发生了Mutations (以异步调用为界,但内部没有异步调用以允许交织),我认为应该没问题.请注意,在您的示例中,a并不是真正的异步,而b是在最终等待之前调用的.

Javascript相关问答推荐

GrapeJS -如何保存和加载自定义页面

jQuery提交按钮重新加载页面,即使在WordPress中使用preventDefault()

自定义高图中的x轴标签序列

Promise Chain中的第二个useState不更新

在react JS中映射数组对象的嵌套数据

如何在ASP.NET JavaScript中使用Google Charts API仅对绘制为负方向的条形图移动堆叠条形图标签位置

第三方包不需要NODE_MODULES文件夹就可以工作吗?

在使用REACT更改了CSS类之后,无法更改CSS样式

搜索功能不是在分页的每一页上进行搜索

使每个<;li>;元素的 colored颜色 与随机生成的 colored颜色 列表不同(不重复

JavaScript:如果字符串不是A或B,则

Clip-Path在网页浏览器(Mozilla、Edge、Chrome)上不能正常工作,但在预览版Visual Code Studio HTML、CSS、JS上却能很好地工作

P5JS-绘制不重叠的圆

我怎样才能点击一个元素,并获得一个与 puppeteer 师导航页面的URL?

如何在移动设备中使用JAVASSCRIPT移除点击时的焦点/悬停状态

React数组查找不读取变量

Played link-Initialize.js永远显示加载符号

不允许在对象文本中注释掉的属性

如何动态呈现适合未知屏幕大小的最大数量的表行?苗条的

对象作为react 子对象无效(已找到:具有键的对象{type,props}).如果要呈现一个子级集合,请改用数组