Last active
December 5, 2017 05:46
-
-
Save xialvjun/3c218668a32c932c35684911c7305ae9 to your computer and use it in GitHub Desktop.
just a sample to show how to implement a js dataloader like facebook/dataloader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const DataLoader = require('dataloader'); | |
const { knex } = require('./singleton.js'); | |
function middleware(ctx, next) { | |
const target = {}; | |
const handler = { | |
get: function (receiver, table_name$key_column_name$) { | |
if (receiver[table_name$key_column_name$]) { | |
return receiver[table_name$key_column_name$]; | |
} | |
const [table_name, key_column_name, single] = table_name$key_column_name$.split('$'); | |
const is_single = single === undefined; | |
const loader = receiver[table_name$key_column_name$] = new DataLoader(async keys => { | |
const objs = await knex(table_name).whereIn(key_column_name, keys); | |
if (is_single) { | |
return keys.map(key => objs.find(obj => obj[key_column_name] === key) || null); | |
} | |
return keys.map(key => objs.filter(obj => obj[key_column_name] === key)); | |
}); | |
return loader; | |
}, | |
}; | |
// 用 Proxy 得到在运行时直接根据调用属性名得到 dataloader,用 memoize 在一次请求中保留 dataloader。。。 | |
// 这里的 dataloader 都只 load 一张表,因为根据多表 load 比较麻烦,而且会用到 join,性能低。。。不过可以后续研究一下。。。 | |
// 最好也只用单表 dataloader。这样可能更好,更清晰。一对多关联,就两个 dataloader 就是;多对多关联,那就三个。清晰的很。。。。 | |
// 而且也能很好的 dataloader 重用,如果使用跨表 dataloader,可能随着 load 的方向的不同,最终的 dataloader 数量比单表 dataloader 还多。。。 | |
// 属性名规则:table_name$key_column_name$ | |
// 用 美元符号 $ 分隔。。。如果结尾是 $,则认为是获取数组,即 loader.load(id) 结果是数组,即该字段是外键,且可重复。。。 | |
// 这里可能使用 _by_ 比用 $ 更好: | |
// 用 _by_ 太长,不过更语义化,但是还要用个东西表示复数; | |
// 用 $ 倒是短,但是双击选择麻烦,而且 $ 在很多语言中不是合法标识符。 | |
ctx.loaders = new Proxy(target, handler); | |
return next(); | |
} | |
module.exports = middleware; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function new_dataloader(fn) { | |
let to_resolve_promise = {} | |
let cache = {} | |
let started = false | |
return { | |
load(id) { | |
if (cache[id]) { | |
return Promise.resolve(cache[id]); | |
} | |
if (!started) { | |
setTimeout(function() { | |
let ids = Object.keys(to_resolve_promise) | |
fn(ids).then(rs => { | |
if (ids.length !== rs.length) { | |
ids.forEach(id => to_resolve_promise[id].forEach(p => p.reject('长度不一致'))) | |
} else { | |
ids.forEach((id, index) => { | |
cache[id] = rs[index] | |
to_resolve_promise[id].forEach(p => p.resolve(rs[index])) | |
}) | |
} | |
}) | |
}, 0); | |
} | |
return new Promise((resolve, reject)=>{ | |
to_resolve_promise[id] = [].concat(to_resolve_promise[id]).concat({resolve, reject}) | |
}); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment