-
Notifications
You must be signed in to change notification settings - Fork 71
/
Copy pathpromise-tracker.js
130 lines (107 loc) · 3.95 KB
/
promise-tracker.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
angular.module('ajoslin.promise-tracker', [])
.provider('promiseTracker', function() {
var trackers = {};
this.$get = ['$q', '$timeout', function($q, $timeout) {
function cancelTimeout(promise) {
if (promise) {
$timeout.cancel(promise);
}
}
return function PromiseTracker(options) {
options = options || {};
//Array of promises being tracked
var tracked = [];
var self = {};
//Allow an optional "minimum duration" that the tracker has to stay active for.
var minDuration = options.minDuration;
//Allow a delay that will stop the tracker from activating until that time is reached
var activationDelay = options.activationDelay;
var minDurationPromise;
var activationDelayPromise;
self.active = function() {
//Even if we have a promise in our tracker, we aren't active until delay is elapsed
if (activationDelayPromise) {
return false;
}
return tracked.length > 0;
};
self.tracking = function() {
//Even if we aren't active, we could still have a promise in our tracker
return tracked.length > 0;
};
self.trackingCount = function() {
return tracked.length;
};
self.destroy = self.cancel = function() {
minDurationPromise = cancelTimeout(minDurationPromise);
activationDelayPromise = cancelTimeout(activationDelayPromise);
for (var i=tracked.length-1; i>=0; i--) {
tracked[i].resolve();
}
tracked.length = 0;
};
//Create a promise that will make our tracker active until it is resolved.
// @return deferred - our deferred object that is being tracked
self.createPromise = function() {
var deferred = $q.defer();
tracked.push(deferred);
//If the tracker was just inactive and this the first in the list of
//promises, we reset our delay and minDuration
//again.
if (tracked.length === 1) {
if (activationDelay) {
activationDelayPromise = $timeout(function() {
activationDelayPromise = cancelTimeout(activationDelayPromise);
startMinDuration();
}, activationDelay);
} else {
startMinDuration();
}
}
deferred.promise.then(onDone(false), onDone(true));
return deferred;
function startMinDuration() {
if (minDuration) {
minDurationPromise = $timeout(angular.noop, minDuration);
}
}
//Create a callback for when this promise is done. It will remove our
//tracked promise from the array if once minDuration is complete
function onDone(isError) {
return function(value) {
(minDurationPromise || $q.when()).then(function() {
var index = tracked.indexOf(deferred);
tracked.splice(index, 1);
//If this is the last promise, cleanup the timeouts
//for activationDelay
if (tracked.length === 0) {
activationDelayPromise = cancelTimeout(activationDelayPromise);
}
});
};
}
};
self.addPromise = function(promise) {
if (Array.isArray(promise)) {
return $q.all(promise.map(self.addPromise));
}
promise = promise && (promise.$promise || promise) || {};
if (!promise.then) {
throw new Error("promiseTracker#addPromise expects a promise object!");
}
var deferred = self.createPromise();
//When given promise is done, resolve our created promise
//Allow $then for angular-resource objects
promise.then(function success(value) {
deferred.resolve(value);
return value;
}, function error(value) {
deferred.reject(value);
return $q.reject(value);
});
return deferred;
};
return self;
};
}];
});