【发布时间】:2019-06-10 09:04:36
【问题描述】:
总结
node.js 中的函数式编程是否足够通用?它可以用来解决处理小批量数据库记录的实际问题,而无需使用toArray 将所有记录加载到内存中(因此内存不足)。你可以阅读this criticism for background。我们想通过异步生成器演示此类 node.js 库的 Mux and DeMux 和 fork/tee/join 功能。
上下文
我质疑在 node.js 中使用任何函数式编程工具(如 ramda、lodash 和 imlazy)甚至自定义函数式编程的有效性和通用性。
给定
来自 MongoDB 游标的数百万条记录可以使用 await cursor.next() 进行迭代
您可能想read more about async generators and for-await-of。
对于可以使用的假数据(在节点 10 上)
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function* getDocs(n) {
for(let i=0;i<n;++i) {
await sleep(1);
yield {i: i, t: Date.now()};
}
}
let docs=getDocs(1000000);
通缉
我们需要
- 第一个文档
- 最后一个文档
- 文档数量
- 分成 n 个文档的批次/批量,并为该批量发出 socket.io 事件
确保第一个和最后一个文档包含在批次中并且没有被消耗。
约束
数以百万计的记录不应该加载到 ram 中,一个应该迭代它们并且最多只保存一批。
该要求可以使用通常的 nodejs 代码来完成,但可以使用诸如 here 中的 applyspec 之类的东西来完成。
R.applySpec({
first: R.head(),
last: R.last(),
_:
R.pipe(
R.splitEvery(n),
R.map( (i)=> {return "emit "+JSON.stringify(i);})
)
})(input)
【问题讨论】:
-
您能否澄清实际问题?更多的是关于“这可以在功能上完成”还是“如何在功能上做到这一点”或“在功能上这样做不好”?
-
也就是说,所提到的问题确实暗示了诸如流和惰性评估之类的词(我在这里故意含糊其辞),并且没有什么能阻止您以功能方式执行此操作。
-
是否让 Javascript 中的函数式编程与在 clojure 或 Haskell 中一样有趣?不,这更费力,因为您无法使用丰富的工具集。如果你不喜欢这样,可以使用 JS 作为编译目标。
-
无论您的范例是否有效,您打算如何执行此操作:“确保第一个和最后一个文档包含在批次中并且不被消耗?”获得第一个是合理的;你只需要在整个过程中保持参考,但最后一个要困难得多。如果你能在其他范式中展示你是如何做到这一点的,也许我们可以提出一个功能性的替代方案。
-
即使是铁杆函数式程序员也会在情况允许时牺牲性能。将退化的情况弯曲成一个人为的函数解决方案可能是一个有趣的难题,但这不是我们在生产中所做的。
标签: node.js functional-programming lodash ramda.js