dataloader如何缓存和批量请求并存储在密钥中。
https://github.com/facebook/dataloader
这里我需要dataloader包并创建一个实例,但它如何工作aby Ideas .............................. .....请为数据库查询,提供db find table
的示例 var DataLoader = require('dataloader')
var userLoader = new DataLoader(keys => myBatchGetUsers(keys));
userLoader.load(1)
.then(user => userLoader.load(user.invitedByID))
.then(invitedBy => console.log(`User 1 was invited by ${invitedBy}`));
// Elsewhere in your application
userLoader.load(2)
.then(user => userLoader.load(user.lastInvitedID))
.then(lastInvited => console.log(`User 2 last invited ${lastInvited}`));
答案 0 :(得分:2)
来自Facebook的DataLoader实用程序的工作原理是将输入请求与您必须提供的批处理功能相结合。它仅适用于使用Identifiers
。
分为三个阶段:
Loader
对象上的任何请求都会延迟到process.nextTick
Loader
只需使用所有请求的密钥组合调用您提供的myBatchGetUsers
功能。这就是为什么在您提供的示例中,您应该只有两个请求:
invitedByID
)要使用mongodb实现此功能,您应该只定义myBatchGetUsers函数以适当地使用find
方法:
function myBatchGetUsers(keys) {
// usersCollection is a promisified mongodb collection
return usersCollection.find(
{
_id: { $in: keys }
}
)
}
答案 1 :(得分:0)
我发现重新创建我使用的dataloader
部分很有帮助,以了解实现它的一种可能方式。 (就我而言,我仅使用.load()
函数)
因此,创建DataLoader
构造函数的新实例将为您带来两件事:
构造函数可能看起来像这样:
function DataLoader (_batchLoadingFn) {
this._keys = []
this._batchLoadingFn = _batchLoadingFn
}
DataLoader
构造函数的实例可以访问.load()
函数,该函数必须能够访问_keys
属性。因此它是在DataLoad.prototype
对象上定义的:
DataLoader.prototype.load = function(key) {
// this._keys references the array defined in the constructor function
}
通过DataLoader构造函数(new DataLoader(fn)
创建新对象时,传递的fn
需要从某处获取数据,以键数组作为参数,并返回一个可解析的Promise到与键的初始数组相对应的值数组。
例如,这是一个伪函数,它接收一个键数组,并将相同的数组传回,但值加倍:
const batchLoadingFn = keys => new Promise( resolve => resolve(keys.map(k => k * 2)) )
keys: [1,2,3]
vals: [2,4,6]
keys[0] corresponds to vals[0]
keys[1] corresponds to vals[1]
keys[2] corresponds to vals[2]
然后,每次调用.load(indentifier)
函数时,都将一个键添加到_keys
数组中,并在某个时刻调用batchLoadingFn
并将其传递给{{1} }数组作为参数。
诀窍是... 如何多次调用_keys
,而.load(id)
仅执行一次?这很酷,也是我探索该库工作原理的原因。
我发现可以通过指定在超时后执行batchLoadingFn
来执行此操作,但是如果在超时间隔之前再次调用batchLoadingFn
,则取消超时,这是一个新键已添加,并重新安排了对.load()
的调用。在代码中实现这一点看起来像这样:
batchLoadingFn
本质上调用DataLoader.prototype.load = function(key) {
clearTimeout(this._timer)
this.timer = setTimeout(() => this.batchLoadingFn(), 0)
}
会删除对.load()
的挂起调用,然后在事件循环的后面安排对batchLoadingFn
的新调用。这样可以保证如果短时间内多次调用batchLoadingFn
,.load()
仅被调用一次。实际上,这与防弹跳非常相似。或者,至少在构建网站并且您想在batchLoadingFn
事件上做某事时,它很有用,但您得到的事件远远超出您想要处理的事件。我认为这称为“反跳”。
但是调用mousemove
还需要将键推入.load(key)
数组,我们可以在_keys
函数体中通过将.load
参数推到{ {1}}(仅key
)。但是,_keys
函数的约定是,它返回与key参数解析的内容有关的单个值。在某个时候,this._keys.push(key)
将被调用并获得结果(它必须返回与.load
相对应的结果)。此外,还要求batchLoadingFn
实际上返回该值的承诺。
我认为接下来的这一点特别聪明(值得看一下源代码)!
_keys
库不是保留batchLoadingFn
中的键列表,而是实际上保留了与对dataloader
函数的引用相关联的键列表,该键列表在调用时会导致作为_keys
结果的解析值。 resolve
返回一个promise,当它的.load()
函数被调用时,promise被解析。
因此,.load()
数组实际上保留了resolve
元组的列表。当您的_keys
返回时,将使用一个值(希望通过索引号与[key, resolve]
数组中的项相对应)调用batchLoadingFn
函数。
因此resolve
函数看起来像这样(就将_keys
元组推入.load
数组而言):
[key, resolve]
剩下的就是用_keys
键作为参数执行DataLoader.prototype.load = function(key) {
const promisedValue = new Promise ( resolve => this._keys.push({key, resolve}) )
...
return promisedValue
}
,并在返回时调用正确的batchLoadingFn
函数
_keys
结合起来,所有实现上述功能的代码都在这里:
resolve
如果我没记错的话,我不认为this._batchLoadingFn(this._keys.map(k => k.key))
.then(values => {
this._keys.forEach(({resolve}, i) => {
resolve(values[i])
})
this._keys = [] // Reset for the next batch
})
库使用function DataLoader (_batchLoadingFn) {
this._keys = []
this._batchLoadingFn = _batchLoadingFn
}
DataLoader.prototype.load = function(key) {
clearTimeout(this._timer)
const promisedValue = new Promise ( resolve => this._keys.push({key, resolve}) )
this._timer = setTimeout(() => {
console.log('You should only see me printed once!')
this._batchLoadingFn(this._keys.map(k => k.key))
.then(values => {
this._keys.forEach(({resolve}, i) => {
resolve(values[i])
})
this._keys = []
})
}, 0)
return promisedValue
}
// Define a batch loading function
const batchLoadingFunction = keys => new Promise( resolve => resolve(keys.map(k => k * 2)) )
// Create a new DataLoader
const loader = new DataLoader(batchLoadingFunction)
// call .load() twice in quick succession
loader.load(1).then(result => console.log('Result with key = 1', result))
loader.load(2).then(result => console.log('Result with key = 2', result))
,而是使用dataloader
。但是我无法解决这个问题。