Skip to content

Commit a3dd591

Browse files
authored
[BREAKING] loadMany() returns individual Error instead of rejecting promise. (#216)
1 parent 2f7af56 commit a3dd591

File tree

4 files changed

+35
-5
lines changed

4 files changed

+35
-5
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ Loads multiple keys, promising an array of values:
341341
const [ a, b ] = await myLoader.loadMany([ 'a', 'b' ])
342342
```
343343

344-
This is equivalent to the more verbose:
344+
This is similar to the more verbose:
345345

346346
```js
347347
const [ a, b ] = await Promise.all([
@@ -350,6 +350,15 @@ const [ a, b ] = await Promise.all([
350350
])
351351
```
352352

353+
However it is different in the case where any load fails. Where
354+
Promise.all() would reject, loadMany() always resolves, however each result
355+
is either a value or an Error instance.
356+
357+
```js
358+
var [ a, b, c ] = await myLoader.loadMany([ 'a', 'b', 'badkey' ]);
359+
// c instanceof Error
360+
```
361+
353362
- *keys*: An array of key values to load.
354363

355364
##### `clear(key)`

src/__tests__/dataloader.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@ describe('Primary API', () => {
6262
expect(empty).toEqual([]);
6363
});
6464

65+
it('supports loading multiple keys in one call with errors', async () => {
66+
const identityLoader = new DataLoader(keys =>
67+
Promise.resolve(
68+
keys.map(key => (key === 'bad' ? new Error('Bad Key') : key))
69+
)
70+
);
71+
72+
const promiseAll = identityLoader.loadMany([ 'a', 'b', 'bad' ]);
73+
expect(promiseAll).toBeInstanceOf(Promise);
74+
75+
const values = await promiseAll;
76+
expect(values).toEqual([ 'a', 'b', new Error('Bad Key') ]);
77+
});
78+
6579
it('batches multiple requests', async () => {
6680
const [ identityLoader, loadCalls ] = idLoader<number>();
6781

src/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ declare class DataLoader<K, V, C = K> {
3737
* ]);
3838
*
3939
*/
40-
loadMany(keys: ArrayLike<K>): Promise<V[]>;
40+
loadMany(keys: ArrayLike<K>): Promise<Array<V | Error>>;
4141

4242
/**
4343
* Clears the value at `key` from the cache, if it exists. Returns itself for

src/index.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,22 @@ class DataLoader<K, V, C = K> {
120120
*
121121
* var [ a, b ] = await myLoader.loadMany([ 'a', 'b' ]);
122122
*
123-
* This is equivalent to the more verbose:
123+
* This is similar to the more verbose:
124124
*
125125
* var [ a, b ] = await Promise.all([
126126
* myLoader.load('a'),
127127
* myLoader.load('b')
128128
* ]);
129129
*
130+
* However it is different in the case where any load fails. Where
131+
* Promise.all() would reject, loadMany() always resolves, however each result
132+
* is either a value or an Error instance.
133+
*
134+
* var [ a, b, c ] = await myLoader.loadMany([ 'a', 'b', 'badkey' ]);
135+
* // c instanceof Error
136+
*
130137
*/
131-
loadMany(keys: $ReadOnlyArray<K>): Promise<Array<V>> {
138+
loadMany(keys: $ReadOnlyArray<K>): Promise<Array<V | Error>> {
132139
if (!isArrayLike(keys)) {
133140
throw new TypeError(
134141
'The loader.loadMany() function must be called with Array<key> ' +
@@ -138,7 +145,7 @@ class DataLoader<K, V, C = K> {
138145
// Support ArrayLike by using only minimal property access
139146
const loadPromises = [];
140147
for (let i = 0; i < keys.length; i++) {
141-
loadPromises.push(this.load(keys[i]));
148+
loadPromises.push(this.load(keys[i]).catch(error => error));
142149
}
143150
return Promise.all(loadPromises);
144151
}

0 commit comments

Comments
 (0)