1 | /*
|
2 | This is free and unencumbered software released into the public domain.
|
3 |
|
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
|
5 | distribute this software, either in source code form or as a compiled
|
6 | binary, for any purpose, commercial or non-commercial, and by any
|
7 | means.
|
8 |
|
9 | In jurisdictions that recognize copyright laws, the author or authors
|
10 | of this software dedicate any and all copyright interest in the
|
11 | software to the public domain. We make this dedication for the benefit
|
12 | of the public at large and to the detriment of our heirs and
|
13 | successors. We intend this dedication to be an overt act of
|
14 | relinquishment in perpetuity of all present and future rights to this
|
15 | software under copyright law.
|
16 |
|
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
23 | OTHER DEALINGS IN THE SOFTWARE.
|
24 |
|
25 | For more information, please refer to <http://unlicense.org/>
|
26 | */
|
27 | // see: https://github.com/nodejs/node/issues/17469#issuecomment-685216777
|
28 | // see: https://github.com/ReactiveX/IxJS/pull/323
|
29 | function isPrimitive(value) {
|
30 | return value === null || (typeof value !== 'object' && typeof value !== 'function');
|
31 | }
|
32 | // Keys are the values passed to race, values are a record of data containing a
|
33 | // set of deferreds and whether the value has settled.
|
34 | const wm = new WeakMap();
|
35 | export function safeRace(contenders) {
|
36 | let deferred;
|
37 | const result = new Promise((resolve, reject) => {
|
38 | deferred = { resolve, reject };
|
39 | for (const contender of contenders) {
|
40 | if (isPrimitive(contender)) {
|
41 | // If the contender is a primitive, attempting to use it as a key in the
|
42 | // weakmap would throw an error. Luckily, it is safe to call
|
43 | // `Promise.resolve(contender).then` on a primitive value multiple times
|
44 | // because the promise fulfills immediately.
|
45 | Promise.resolve(contender).then(resolve, reject);
|
46 | continue;
|
47 | }
|
48 | let record = wm.get(contender);
|
49 | if (record === undefined) {
|
50 | record = { deferreds: new Set([deferred]), settled: false };
|
51 | wm.set(contender, record);
|
52 | // This call to `then` happens once for the lifetime of the value.
|
53 | Promise.resolve(contender).then((value) => {
|
54 | // eslint-disable-next-line no-shadow
|
55 | for (const { resolve } of record.deferreds) {
|
56 | resolve(value);
|
57 | }
|
58 | record.deferreds.clear();
|
59 | record.settled = true;
|
60 | }, (err) => {
|
61 | // eslint-disable-next-line no-shadow
|
62 | for (const { reject } of record.deferreds) {
|
63 | reject(err);
|
64 | }
|
65 | record.deferreds.clear();
|
66 | record.settled = true;
|
67 | });
|
68 | }
|
69 | else if (record.settled) {
|
70 | // If the value has settled, it is safe to call
|
71 | // `Promise.resolve(contender).then` on it.
|
72 | Promise.resolve(contender).then(resolve, reject);
|
73 | }
|
74 | else {
|
75 | record.deferreds.add(deferred);
|
76 | }
|
77 | }
|
78 | });
|
79 | // The finally callback executes when any value settles, preventing any of
|
80 | // the unresolved values from retaining a reference to the resolved value.
|
81 | return result.finally(() => {
|
82 | for (const contender of contenders) {
|
83 | if (!isPrimitive(contender)) {
|
84 | const record = wm.get(contender);
|
85 | record.deferreds.delete(deferred);
|
86 | }
|
87 | }
|
88 | });
|
89 | }
|
90 |
|
91 | //# sourceMappingURL=safeRace.mjs.map
|