NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #2460 most downloaded on npm
A data loading utility to reduce requests to a backend via batching and caching.
Last release 2 years ago
no release in 18 months
Release timing varies
gaps range from 2 weeks to 2.4 years
Nearly every release is documented
notes for 11 of 11 stable releases
Nothing withdrawn
no release was ever pulled
11 years old
11 releases · first in 2015
refactor: replace var statements with const or let statements by @shogo-nakano-desu in #337
Full Changelog: v2.2.2...v2.2.3
One column per quarter.
fix: expose name in Dataloader instance types by @henrinormak in #334
name in Dataloader instance types by @henrinormak in #334Full Changelog: v2.2.1...v2.2.2
e286f66 Thanks @henrinormak! - Added missing type definition for Dataloader.namefix: TS types for the new name property by @saihaj in #331
fix: incorrect variable name in README.md by @danielcaballero in #313
name to DataLoader by @SimenB in #326Full Changelog: v2.1.0...v2.2.0
588a8b6 Thanks @boopathi! - Fix the propagation of sync throws in the batch function to the loader function instead of crashing the process wtih an uncaught exception.3cd3a43 Thanks @thekevinbrown! - Resolves an issue where the maxBatchSize parameter wouldn't be fully used on each batch sent to the backend loader.28cf959 : - Do not return void results from arrow functions 3b0bae9
loader.load() error message 249b2b9setImmediate. setImmediate || setTimeout doesn't work and it throws setImmediate is not defined in this case, so we should check setImmediate with typeof. And some environments like Cloudflare Workers don't allow you to set setTimeout directly to another variable. 3e62fbeloader.load() error message https://github.com/graphql/dataloader/commit/249b2b966a8807c50e07746ff04acb8c48fa4357setImmediate. setImmediate || setTimeout doesn't work and it throws setImmediate is not defined in this case, so we should check setImmediate with typeof. And some environments like Cloudflare Workers don't allow you to set setTimeout directly to another variable. https://github.com/graphql/dataloader/commit/3e62fbe7d42b7ab1ec54818a1491cb0107dd828aThis is the first release since becoming part of the GraphQL Foundation and the most significant since the initial release over four years ago. Read m
This is the first release since becoming part of the GraphQL Foundation and the most significant since the initial release over four years ago. Read more about the history of the project and this release in the blog post.
Breaking:
.loadMany() now returns an array which may contain Error if one of the requested keys failed.
Previously
.loadMany()was exactly the same as callingPromise.all()on multiple.load()calls. While syntactically a minor convenience, this wasn't particularly useful over what could be done withPromise.alldirectly and if one key failed, it meant the entire call to.loadMany()would fail. As of this version,.loadMany()can now return a mix of values andErrorinstances in the case that some keys failed, but the Promise it returns will never be rejected. This is similar to the behavior of the new Promise.allSettled method in the upcoming version of JavaScript.This will break any code which relied on
.loadMany(). To support this change, either ensure the each item in the result of.loadMany()are checked againstinstanceof Erroror replace calls likeloader.loadMany([k1, k2])withPromise.all([loader.load(k1), loader.load(k2)).
batchLoadFn when { batch: false } has changed to the end of the run-loop tick.
Previously when batching was disabled the
batchLoadFnwould be called immediately when.load()is called. This differed from thebatchLoadFnbeing called at the end of the tick of the run-loop for when batching was enabled. This timing difference could lead to subtle race conditions for code which dynamically toggled batching on or off. As a simplification, thebatchLoadFnis now always called at the end of the run-loop tick regardless of whether batching is disabled.Hopefully this will not break your code. It could cause issues for any code which relied on this synchronous call to
batchLoadFnfor loaders where batching was disabled.
Previously when
.load()encountered a cached value it would return an already resolved (or rejected) Promise. However when additional dependent loads happened after these, the difference in time between the cache hit value resolving and the cache miss value resolving would result in additional unnecessary network requests. As of this version when.load()encounters a cached value it returns a Promise which waits to resolve until the call tobatchLoadFnalso resolves. This should result in better whole-program performance and is the most significant conceptual change and improvement. This is actually not a new innovation but a correction to match the original behavior of Facebook's "Loader" from 2010 this library is inspired by.This changes the timing of when Promises are resolved and thus could introduce subtle behavioral change in your code, especially if your code is prone to race conditions. Please test carefully.
This also means each return of
.load()is a new Promise instance. Where prior versions returned the same Promise instance for cached results, this version does not. This may break code which uses the returned Promise as a memoization key or in some other way assumed reference equality.
This really shouldn't break your code because you definitely don't reach into class private variables, right? I just figured it would be something you'd like to know, you know... just in case.
New:
this in batchLoadFnThe dirty secret of DataLoader is that most of it is quite boring. The interesting bit is the batch scheduling function which takes advantage of Node.js's unique run-loop scheduler to acheive automatic batching without any additional latency. However since its release, ports to other languages have found this bit to be not be easily replicated and have either replaced it with something conceptually simpler (like manual dispatch) or with a scheduler custom fit to a GraphQL execution engine. These are interesting innovations which deserve ground for experimentation in this original library as well.
Via
batchScheduleFn, you can now provide a custom batch scheduling function and experiment with manual dispatch, added latency dispatch, or any other behavior which might work best for your application.
Types:
cacheKeyFn and cacheMapbatchLoadFn to return a PromiseLike, supporting use of bluebirdbatchLoadFn to return ArrayLike, supporting returning read-only arraysError to .prime()Fixes:
Error to .prime() could incorrectly cause an unhandled promise rejection warningDocumentation:
cacheMap along with an LRU example.batchLoadFn.batchLoadFn.Direct support for using Dataloader in a browser
New:
Note: Dataloader in the browser cannot rely on the same post-promise job queuing behavior that allows for best performance in Node environments. A fallback behavior is used in a browser.
This leads to better error messages when in use with custom caches that do not provide the full required interface. It may now produce eager errors where latent bugs were allowed in prior versions.
Fixed:
require("dataloader") (#135)Due to more recent versions of Flow treating
Arrayas invariant, DataLoader uses$ReadOnlyArraywhich is covariant.
Thanks to contributions from many, the documentation for DataLoader is now significantly better, with portions of README.md reworked and improved and
New:
README.md reworked and improved and more information in examples/.Prime values in the cache - #18 . — If you have values cached locally, this provides an API for adding those already known values to a DataLoader cach
New:
Prime values in the cache - #18. — If you have values cached locally, this provides an API for adding those already known values to a DataLoader cache:
let loader = new DataLoader(keys => promiseToGetKeys(keys));
loader.prime('abc', 'My Value');
loader.load('abc').then(val => console.log(val)); // Logs "My Value"This also works for priming errors:
let loader = new DataLoader(keys => promiseToGetKeys(keys));
loader.prime('abc', new Error('My Error'));
loader.load('abc').catch(err => console.log(err)); // Logs "My Error"This is particularly useful for allowing two loaders to interact based on two fetchable keys for one type:
let userByIDLoader = new DataLoader(ids => promiseToGetByID(ids).then(users => {
for (let user of users) {
userByUsernameLoader.prime(user.username, user);
}
return users;
}));
let userByUsernameLoader = new DataLoader(names => promiseToGetByUsername(names).then(users => {
for (let user of users) {
userByIDLoader.prime(user.id, user);
}
return users;
}));Provide a custom cache-key function. #15 — Since JavaScript does not use value equality, but fetch keys are often treated as values, this allows for a
New:
Provide a custom cache-key function. #15 — Since JavaScript does not use value equality, but fetch keys are often treated as values, this allows for a custom function to be provided to produce a cache-key for any load-key. Example:
var loader = new DataLoader(keys => promiseToGetKeys(keys), { cacheKeyFn: key => key._id });
var first = loader.load({ _id: 'abc123' });
var second = loader.load({ _id: 'abc123' });
assert(first === second);Provide a custom cache instance. #17 — By default, DataLoader uses a Map as a cache. However this simple cache does not support anything like TTL or a cache eviction policy. Now you may provide any object which implements the Map API to use as a cache. Example:
var loader = new DataLoader(keys => promiseToGetKeys(keys), { cacheMap: new LRUCacheMap() });Initial release! See README.md for API details and please report bugs using github issues.
Initial release! See README.md for API details and please report bugs using github issues.
Your coding agent can read these notes before it upgrades. Set up the MCP server →