Adding B-Threads Dynamically¶
Let’s count to 4 in an arbitrary order! That is, let’s have 4 events, labeled e0
to e3
, and not care about the order in which they occur. For this, we need four b-threads, each requesting a numbered event. But since they all do the same, we might want to create them from a loop, like so:
1 2 3 4 5 6 | var COUNT=4;
for ( var i=0; i<COUNT; i++ ) {
bp.registerBThread("requestor-"+i, function(){
bp.sync({request:bp.Event("e"+i)});
});
};
|
If we run this, however, we do not get what we want:
1 $ java -jar BPjs.jar dynamic-bthread-bad.js 2 # [READ] /.../dynamic-bthread-bad.js 3 -:BPjs Added requestor-0 4 -:BPjs Added requestor-1 5 -:BPjs Added requestor-2 6 -:BPjs Added requestor-3 7 # [ OK ] dynamic-bthread-bad.js 8 ---:BPjs Started 9 --:BPjs Event [BEvent name:e4] 10 ---:BPjs No Event Selected 11 ---:BPjs Ended
This may seem weird: in lines 3 to 6, the value of i
goes from 0 to 3, as expected. But there’s only one event selected, and it’s e4
.
The reason for this is that Javascript is a late-binding language, so i
’s value is looked up as late as possible. For the logging, i
has to be evaluated immediately, while the runtime builds a string to pass to the logger. The call to bp.Event("e"+i)
, on the other hand, is evaluated only when the b-thread is started.
Alas, the b-thread is started after the javascript file is evaluated. At this point, i
is equal to 4. So in effect, we had four b-threads, named requestor-0
to requestor-3
, all asking for event e4
.
To get four different events, we need to create a scope for each iteration. This is easy, since Javascript supports functions as first-class-citizens (source
).
1 2 3 4 5 6 7 8 | var COUNT=4;
for ( var i=0; i<COUNT; i++ ) {
(function(j){
bp.registerBThread("requestor-" + j, function(){
bp.sync({request:bp.Event("e"+j)});
});
})(i);
};
|
Lines 4-6 are the same as before, but now they are wrapped in an anonymous function (line 3) that’s immediately called, with i
as the parameter (line 7). This results in the b-thread function having its own scope (or, to be technically exact, activation object). That scope keeps the value of i
at the iteration the scope was created in - that value is put in the parameter j
.
Thus, each b-thread gets its own scope and correct value of i
(except that it’s calling it j
at this point).
$ java -jar BPjs.jar dynamic-bthread-ok.js
# [READ] /.../dynamic-bthread-ok.js
-:BPjs Added requestor-0
-:BPjs Added requestor-1
-:BPjs Added requestor-2
-:BPjs Added requestor-3
# [ OK ] dynamic-bthread-ok.js
---:BPjs Started
--:BPjs Event [BEvent name:e2]
--:BPjs Event [BEvent name:e1]
--:BPjs Event [BEvent name:e3]
--:BPjs Event [BEvent name:e0]
---:BPjs No Event Selected
---:BPjs Ended