-
Notifications
You must be signed in to change notification settings - Fork 0
/
waitsync.js
178 lines (150 loc) · 4.15 KB
/
waitsync.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/**
* WaitSync class provides synchronization between group of
* two or more functions which you plan to call asyncronously.
* @param Function callback The callback function to be executed after
* the group of functions is executed
*
* @version 0.4
* @example
*
* var chef = new WaitSync(
* function () {
* alert('Cook noodles');
* }
* );
*
* // son will finish chopping in like 4 seconds
* setTimeout(
* chef.wait(function () {
*
* // when meat is done
* alert('Meat is ready');
* }),
*
* Math.floor(Math.random()*4000)
* );
*
* // daughter will finish cutting soon
* setTimeout(
* chef.wait(function () {
*
* // prepare vegetables
*
* alert('Vegetables are ready');
* }),
* Math.floor(Math.random()*4000)
* );
*
* var soupWithNoodles = false;
* if (soupWithNoodles) {
* setTimeout(
* chef.wait(function () {
* alert('Noodles are ready');
* }),
* 1000
* );
* }
*/
function WaitSync(callback) {
var completeCount = 0;
var flags = {};
// task return values will be stored here
// and will be passed to callback as argument
var buffer = {
'order': [],
'groupOrder': [],
'data': {}
};
/**
* Wrap task with callback
* @param Function task
* @param Object ctx Context. Object which will be referenced "this"
* inside the task. For those who know the indepths of JS OOP
* @return Function
*/
var wrapOne = function (task, ctx) {
// remember in which order did we come in
var whoAmI = completeCount;
// add count
completeCount ++;
var iAmDone = false;
return function () {
// proxy, buffer
var tmp = task.apply(ctx, arguments);
// log the result
buffer.order.push(whoAmI);
// just returns result if the same task called twice
// actually it means your design needs some refactoring
if (iAmDone)
return tmp;
// is it time to call back? :)
completeCount--;
iAmDone = true;
if (completeCount === 0)
callback(buffer);
return tmp;
}
};
/**
* Wrap task with potential callback and assign it a certain group.
* Several tasks may be grouped.
* When task is finished, it's whole group is considered to be done.
* It's like... wait for one of the group to be complete.
* @param Number/String groupName a name of the group
* @param Function task
* @param Object ctx Context. An object which will be referenced "this"
* inside the task
* @return Function
*/
var wrapGroup = function (groupName, task, ctx) {
// if not created earlier
if (flags[groupName] !== false) {
// set task group uncomplete
flags[groupName] = false;
completeCount ++;
}
// to prevent doubletriggerring (actually not necessary here)
var iAmDone = false;
return function () {
var tmp = task.apply(ctx, arguments);
// same as in wrap... just return result if called twice
if (iAmDone)
return tmp;
// only if group is not done
if (!flags[groupName]) {
completeCount--;
flags[groupName] = true;
// log result:
buffer.order.push(groupName);
buffer.groupOrder.push(groupName);
buffer.data[groupName] = tmp;
// is it time?
if (completeCount === 0)
callback(buffer);
}
return tmp;
}
};
/**
* Wrap "task" with callback. Returns a wrapped function to be used
* instead.
*
* @param [optional] String/Number Optional id of the task.
* A "named" task so to say...
* Several tasks may have the same id. In this case whenever
* one of them finishes, the whole group is considered to
* be finished. E.g. ajax success and error callbacks may be
* groupped together so whatever happens, the callback will
* be fired.
* @param Function task Function to be wrapped
* @param Object ctx Context. An object which will be referenced "this"
* inside the task
* @return Function a wrapped function.
*/
this.wrap = function () {
var call = wrapOne;
if (!(arguments[0] instanceof Function) && (arguments[1] instanceof Function))
call = wrapGroup;
return call.apply(this, arguments);
}
}