[英]How to deal with race conditions in javascript?
First off all, I'm a pythonist, not a javascripter - please be kind. 首先,我是一个蟒蛇,而不是一个javascripter - 请善待。
In a popular MVVM Javascript framework from a popular Internet search provider , there is a class called Scope. 在流行的Internet搜索提供程序的流行MVVM Javascript 框架中 ,有一个名为Scope的类。
This class has a method called $watch
, used to register callbacks (called listeners) that are supposed to be called every time that Scope.$digest
is fired. 这个类有一个名为
$watch
的方法,用于注册每次触发Scope.$digest
时应该调用的回调(称为侦听器)。 Calls to Scope.$watch
returns a deregistration function for this listener. 调用
Scope.$watch
返回此侦听器的注销函数。
Listeners are called in the following loop: 在以下循环中调用侦听器:
...
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)
...
Since a listener can be registered or destroyed from another listener, there are two race conditions here : 由于侦听器可以从另一个侦听器注册或销毁, 因此这里有两种竞争条件 :
length = watchers.length
and watch = watchers[length]
, watch
will be undefined and the call to watch.get(current)
will fail (undefined has no method get). length = watchers.length
和watch = watchers[length]
watch.get(current)
watch = watchers[length]
之间注销时, watch
将是未定义的,并且对watch.get(current)
的调用将失败(undefined没有方法get)。 I guess a simple check for the existence of watch
would fix condition #1: 我猜一个关于
watch
存在的简单检查会解决条件#1:
if (watch && (value = watch.get(current)) !== (last = watch.last)
I'm not sure how to solve condition #2. 我不确定如何解决条件#2。 Shall not modify an array while iterating over it - my first thought was: why
while (length--)
? 迭代时不应修改数组 - 我的第一个想法是:为什么
while (length--)
? Then I read in the source comments: 然后我在源评论中读到:
- Loop operations are optimized by using while(count--) { ... }
使用while(count--){...}优化循环操作
- this means that in order to keep the same order of execution as addition we have to add items to the array at the beginning (shift) instead of at the end (push)
这意味着为了保持与添加相同的执行顺序,我们必须在开头(shift)而不是在结尾(push)将数据添加到数组中
In Python I would probably try to solve it using queues. 在Python中,我可能会尝试使用队列来解决它。 Two questions:
两个问题:
[edit] [编辑]
Samuel Neff commented that since JavaScript is not multi-threaded, this is not really a race condition. Samuel Neff评论说,由于JavaScript不是多线程的,因此这不是真正的竞争条件。
A more objective question is: with performance and memory footprint in mind, what can I do to prevent bugs caused by a callback that modifies the very array I'm iterating over when using the while (length--)
pattern to loop over an array of callbacks? 一个更客观的问题是:考虑到性能和内存占用,我可以做些什么来防止回调引起的错误修改我正在迭代的数组,当使用
while (length--)
模式循环数组时回调?
JavaScript is not multi-threaded. JavaScript不是多线程的。 You don't have to worry about another "thread" modifying the objects between sequential lines of code.
您不必担心在连续的代码行之间修改对象的另一个“线程”。
It is possible to have race conditions if you depend on callbacks being called back in a particular order, but you don't have to worry about race conditions like in normal multi-threaded languages. 如果您依赖于以特定顺序回调的回调,则可能存在竞争条件,但您不必担心普通多线程语言中的竞争条件。
The way I have solved problems like this a few times in the past (when iterating through connections in server code, for example) is by adding new listeners (or in my case, connections) to a temporary array / "queue." 我过去几次解决这类问题的方式(例如,在服务器代码中迭代连接时)是通过向临时数组/“队列”添加新的侦听器(或者在我的情况下,连接)。
In my main loop I would go first go through the existing connections, deleting the ones which had been marked as dropped and dispatching other threads to deal with connections which needed servicing. 在我的主循环中,我将首先浏览现有连接,删除已标记为已删除的连接并调度其他线程以处理需要服务的连接。 Other threads could register connections to the queue array or mark connections as dropped from the main array but would not actually delete them.
其他线程可以注册到队列数组的连接或标记从主数组中删除的连接,但实际上不会删除它们。 This took care of your first race condition.
这照顾了你的第一场比赛条件。
The second race condition was solved by having my main loop atomically link the queue array to the end of the main array thus starting an empty queue array and extending the main array by the previous contents of the queue array. 第二个竞争条件是通过让我的主循环将队列数组原子地链接到主数组的末尾来解决的,从而启动空队列数组并通过队列数组的先前内容扩展主数组。 The main loop then finished going through the newly extended contents of the main array.
然后主循环完成了主数组的新扩展内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.