3

首先,我是 pythonist,而不是 javascripter - 请善待。

在流行的 Internet 搜索提供商的流行MVVM Javascript框架中,有一个名为 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)
... 

由于可以从另一个侦听器注册或销毁侦听器,因此这里有两个竞争条件

  1. 当侦听器在length = watchers.lengthand之间注销时watch = watchers[length]watch将是未定义的并且对的调用watch.get(current)将失败(未定义没有方法 get)。
  2. 当一个监听器被另一个监听器注册时,它可能会被跳过。

我想一个简单的检查是否存在watch将修复条件#1:

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

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

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

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

  1. 当目标是最大化性能和节省内存时,在 javascript 中处理这个问题的惯用方法是什么?
  2. 我应该如何进行竞争条件的单元测试(或者我应该使用端到端测试)?

[编辑]

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

一个更客观的问题是:考虑到性能和内存占用,我可以做些什么来防止在使用模式循环遍历回调数组时修改我正在迭代while (length--)的数组的回调引起的错误?

4

2 回答 2

3

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

如果您依赖以特定顺序回调的回调,则可能会出现竞争条件,但您不必像普通多线程语言那样担心竞争条件。

于 2013-06-12T03:57:11.013 回答
1

我过去几次解决此类问题的方法(例如,在通过服务器代码中的连接进行迭代时)是将新的侦听器(或在我的情况下为连接)添加到临时数组/“队列”中。

在我的主循环中,我将首先检查现有连接,删除已标记为已删除的连接并调度其他线程来处理需要服务的连接。其他线程可以将连接注册到队列数组或将连接标记为从主数组中删除,但实际上不会删除它们。这解决了您的第一个比赛条件。

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

于 2013-06-12T04:12:54.340 回答