Skip to content

Commit 7eb76b2

Browse files
committed
Use proper promise idiom in Provider
1 parent 6874e37 commit 7eb76b2

9 files changed

Lines changed: 172 additions & 13 deletions

Gruntfile.coffee

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ module.exports = (grunt) ->
2222

2323
SRC_MODULES =
2424
'filter': ['src/filter/SimpleFilter.js']
25-
'provider': ['src/CommentProvider.js']
25+
'provider': ['src/CommentProvider.js', 'src/Promises.js']
2626
'format-bilibili': ['src/parsers/BilibiliFormat.js']
2727
'format-acfun': ['src/parsers/AcfunFormat.js']
2828
'format-common': ['src/parsers/CommonDanmakuFormat.js']

dist/CommentCoreLibrary.js

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @license MIT
44
* @author Jim Chen
55
*/
6-
var BinArray = (function( ) {
6+
var BinArray = (function () {
77

88
var BinArray = {};
99

@@ -1266,7 +1266,7 @@ var CommentProvider = (function () {
12661266
var promises = [];
12671267
// TODO: This race logic needs to be rethought to provide redundancy
12681268
for (var type in this._staticSources) {
1269-
promises.push(Promise.race(this._staticSources[type])
1269+
promises.push(Promises.any(this._staticSources[type])
12701270
.then(function (data) {
12711271
return this.applyParsersList(data, type);
12721272
}.bind(this)));
@@ -1275,7 +1275,7 @@ var CommentProvider = (function () {
12751275
// No static loaders
12761276
return Promise.resolve([]);
12771277
}
1278-
return Promise.race(promises).then(function (commentList) {
1278+
return Promises.any(promises).then(function (commentList) {
12791279
for (var i = 0; i < this._targets.length; i++) {
12801280
this._targets[i].load(commentList);
12811281
}
@@ -1345,6 +1345,61 @@ var CommentProvider = (function () {
13451345
return CommentProvider;
13461346
})();
13471347

1348+
/**
1349+
* Promises extra functionality
1350+
* @license MIT
1351+
* @author Jim Chen
1352+
*/
1353+
var Promises = (function( ) {
1354+
1355+
var Promises = {};
1356+
1357+
/**
1358+
* Resolves as soon as any promise resolves in the order of the input array
1359+
*
1360+
* @param arr - array of promises
1361+
* @return promise that resolves if any one promise resolves and rejects
1362+
* if otherwise
1363+
**/
1364+
Promises.any = function (promises) {
1365+
if (!Array.isArray(promises)) {
1366+
// Is raw object or promise, resolve it directly
1367+
return Promise.resolve(promises);
1368+
}
1369+
if (promises.length === 0) {
1370+
// No promises to resolve so we think it failed
1371+
return Promise.reject();
1372+
}
1373+
return new Promise(function (resolve, reject) {
1374+
var hasResolved = false;
1375+
var hasCompleted = 0;
1376+
var errors = [];
1377+
for (var i = 0; i < promises.length; i++) {
1378+
promises[i].then(function (value) {
1379+
hasCompleted++;
1380+
if (!hasResolved) {
1381+
hasResolved = true;
1382+
resolve(value);
1383+
}
1384+
}).catch((function (i) {
1385+
return function (e) {
1386+
hasCompleted++;
1387+
errors[i] = e;
1388+
if (hasCompleted === promises.length) {
1389+
// All promises have completed and we are in rejecting case
1390+
if (!hasResolved) {
1391+
reject(errors);
1392+
}
1393+
}
1394+
}
1395+
})(i));
1396+
}
1397+
});
1398+
};
1399+
1400+
return Promises;
1401+
})();
1402+
13481403
/**
13491404
* Bilibili Format Parser
13501405
* Takes in an XMLDoc/LooseXMLDoc and parses that into a Generic Comment List

dist/CommentCoreLibrary.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

spec/CommentProvider_spec.coffee

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ describe 'CommentProvider', ->
183183
it 'fails if no sources are available', (done) ->
184184
provider.addStaticSource (Promise.reject 'Error'), CommentProvider.SOURCE_TEXT
185185
provider.load().catch (e) ->
186-
expect(e).toBe 'Error'
186+
expect(e).toBeTruthy()
187187
done()
188188

189189
describe '.start', ->

spec/Promises_spec.coffee

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'use strict'
2+
describe 'Promises', ->
3+
describe 'any', ->
4+
it 'resolves single object', (done) ->
5+
p = Promises.any 'Foo'
6+
p.then (value) ->
7+
expect(value).toBe 'Foo'
8+
done()
9+
10+
it 'rejects single promise', (done) ->
11+
p = Promises.any Promise.reject 'Bar'
12+
p.catch (value) ->
13+
expect(value).toBe 'Bar'
14+
done()
15+
16+
it 'resolves empty', (done) ->
17+
p = Promises.any []
18+
p.catch (e) ->
19+
expect(e).toBeFalsy()
20+
done()
21+
22+
it 'falls back', (done) ->
23+
p = Promises.any [
24+
Promise.reject 'A'
25+
Promise.reject 'B'
26+
Promise.resolve 'C'
27+
]
28+
p.then (value) ->
29+
expect(value).toBe 'C'
30+
done()
31+
32+
it 'resolves on first', (done) ->
33+
p = Promises.any [
34+
Promise.reject 'A'
35+
Promise.resolve 'B'
36+
Promise.resolve 'C'
37+
]
38+
p.then (value) ->
39+
expect(value).toBe 'B'
40+
done()
41+
42+
it 'rejects if none resolve', (done) ->
43+
p = Promises.any [
44+
Promise.reject 'A'
45+
Promise.reject 'B'
46+
Promise.reject 'C'
47+
]
48+
p.catch (errors) ->
49+
expect(errors).toEqual ['A', 'B', 'C']
50+
done()

spec/core/CommentSpaceAllocator_spec.coffee

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ describe 'CommentSpaceAllocators', ->
5252
c1.cindex = -1
5353
expect(typeof anchorCSA.remove(c1)).toBe 'undefined'
5454

55-
it 'removal for cindex < 0', ->
56-
c1.cindex = -1
55+
it 'removal for cindex not found', ->
56+
c1.cindex = 0
5757
expect(typeof anchorCSA.remove(c1)).toBe 'undefined'
5858
# TODO: We need more extensive test cases
5959

@@ -75,7 +75,7 @@ describe 'CommentSpaceAllocators', ->
7575
s1.cindex = -1
7676
expect(typeof scrollCSA.remove(s1)).toBe 'undefined'
7777

78-
it 'removal for cindex < 0', ->
79-
s1.cindex = -1
78+
it 'removal for cindex not found', ->
79+
s1.cindex = 0
8080
expect(typeof scrollCSA.remove(s1)).toBe 'undefined'
8181
# TODO: We need more extensive test cases

src/Array.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @license MIT
44
* @author Jim Chen
55
*/
6-
var BinArray = (function( ) {
6+
var BinArray = (function () {
77

88
var BinArray = {};
99

src/CommentProvider.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ var CommentProvider = (function () {
268268
var promises = [];
269269
// TODO: This race logic needs to be rethought to provide redundancy
270270
for (var type in this._staticSources) {
271-
promises.push(Promise.race(this._staticSources[type])
271+
promises.push(Promises.any(this._staticSources[type])
272272
.then(function (data) {
273273
return this.applyParsersList(data, type);
274274
}.bind(this)));
@@ -277,7 +277,7 @@ var CommentProvider = (function () {
277277
// No static loaders
278278
return Promise.resolve([]);
279279
}
280-
return Promise.race(promises).then(function (commentList) {
280+
return Promises.any(promises).then(function (commentList) {
281281
for (var i = 0; i < this._targets.length; i++) {
282282
this._targets[i].load(commentList);
283283
}

src/Promises.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Promises extra functionality
3+
* @license MIT
4+
* @author Jim Chen
5+
*/
6+
var Promises = (function( ) {
7+
8+
var Promises = {};
9+
10+
/**
11+
* Resolves as soon as any promise resolves in the order of the input array
12+
*
13+
* @param arr - array of promises
14+
* @return promise that resolves if any one promise resolves and rejects
15+
* if otherwise
16+
**/
17+
Promises.any = function (promises) {
18+
if (!Array.isArray(promises)) {
19+
// Is raw object or promise, resolve it directly
20+
return Promise.resolve(promises);
21+
}
22+
if (promises.length === 0) {
23+
// No promises to resolve so we think it failed
24+
return Promise.reject();
25+
}
26+
return new Promise(function (resolve, reject) {
27+
var hasResolved = false;
28+
var hasCompleted = 0;
29+
var errors = [];
30+
for (var i = 0; i < promises.length; i++) {
31+
promises[i].then(function (value) {
32+
hasCompleted++;
33+
if (!hasResolved) {
34+
hasResolved = true;
35+
resolve(value);
36+
}
37+
}).catch((function (i) {
38+
return function (e) {
39+
hasCompleted++;
40+
errors[i] = e;
41+
if (hasCompleted === promises.length) {
42+
// All promises have completed and we are in rejecting case
43+
if (!hasResolved) {
44+
reject(errors);
45+
}
46+
}
47+
}
48+
})(i));
49+
}
50+
});
51+
};
52+
53+
return Promises;
54+
})();

0 commit comments

Comments
 (0)