如何在javascript中处理竞争条件?

时间:2013-06-12 03:42:06

标签: javascript angularjs-directive race-condition

首先,我是一个蟒蛇,而不是一个javascripter - 请善待。

在热门的MVVM Javascript framework from a popular Internet search provider中,有一个名为Scope的类。

此类有一个名为$watch的方法,用于注册每次触发Scope.$digest时应调用的回调(称为侦听器)。对Scope.$watch的调用会返回此侦听器的注销功能。

在以下循环中调用侦听器:

...
do { // "traverse the scopes" loop
  if ((watchers = current.$$watchers)) {
    // process our watches
    length = watchers.length;
    while (length--) {
      try {
        watch = watchers[length];
        // Most common watches are on primitives, in which case we can short
        // circuit it with === operator, only when === fails do we use .equals
          if ((value = watch.get(current)) !== (last = watch.last)
... 

由于可以从另一个侦听器注册或销毁侦听器there are two race conditions here

  1. 当在length = watchers.lengthwatch = watchers[length]之间取消注册某个侦听器时,watch将被取消定义,对watch.get(current)的调用将失败(undefined没有方法获取)。
  2. 当侦听器由另一个侦听器注册时,可以跳过它。
  3. 我想对watch的存在进行简单检查可以解决条件#1:

    if (watch && (value = watch.get(current)) !== (last = watch.last)
    

    我不确定如何解决条件#2。迭代时不应修改数组 - 我的第一个想法是:为什么while (length--)?然后我在源评论中读到:

      
        
    • 使用while(count--){...}
    • 优化循环操作   
      •   
      • 这意味着为了保持与添加相同的执行顺序   我们必须在开头(shift)而不是at处向数组添加项目   结束(推)
      •   
    •   

    在Python中,我可能会尝试使用队列来解决它。两个问题:

    1. 在定位最高性能和内存保护时,在javascript中处理此问题的惯用方法是什么?
    2. 我应该如何针对竞争条件进行单元测试(或者我应该使用端到端测试)?
    3. [编辑]

      Samuel Neff评论说,由于JavaScript不是多线程的,因此这不是真正的竞争条件。

      一个更客观的问题是:考虑到性能和内存占用,我该怎么做才能防止回调导致的错误,这些错误修改了我在使用{{{i}时迭代的数组1}}模式循环回调数组?

2 个答案:

答案 0 :(得分:3)

JavaScript不是多线程的。您不必担心在连续的代码行之间修改对象的另一个“线程”。

如果依赖于以特定顺序回调的回调,则可能存在竞争条件,但您不必担心普通多线程语言中的竞争条件。

答案 1 :(得分:1)

我过去几次解决这类问题的方式(例如,在服务器代码中迭代连接时)是通过向临时数组添加新的侦听器(或者在我的情况下,连接)/#34 ;队列"

在我的主循环中,我将首先浏览现有连接,删除已标记为已删除的连接并调度其他线程以处理需要服务的连接。其他线程可以注册到队列数组的连接或标记从主数组中删除的连接,但实际上不会删除它们。这照顾了你的第一次竞争条件。

通过让我的主循环将队列数组原子地链接到主数组的末尾来解决第二种竞争条件,从而启动空队列数组并通过队列数组的先前内容扩展主数组。然后主循环完成了主数组的新扩展内容。