Node.js设计:多个异步函数使用作为闭包传递的函数写入数据库

Node.js design: multiple async functions writing to database using function passed as a closure

本文关键字:函数 闭包 数据库 设计 js 异步 Node      更新时间:2023-09-26

我正在Node中编写一个独立的web scraper,从命令行运行,它在一组页面上查找特定数据,从Google Analytics获取页面视图数据,并将其全部保存在MySQL数据库中。几乎一切都准备好了,但今天我发现在数据库中写入数据的方式有问题。

为了简化操作,我们假设我有一个index.js文件和两个控制器——dbwebDb向数据库读取/写入数据,web使用可配置数量的PhantomJs实例来废弃页面。

Web公开一个函数checkTargetUrls(urls, writer)其中urls是一个具有要检查的url的数组,writer是一个可选参数,仅当它是一个函数并且有要写入的数据时才调用。

现在,我通过编写器的方式显然是错误的,但看起来如下(在index.js中):

some code here
....
let pageId = 0;
... some promises code,
which checks validy of urls, 
creates new execution in the database, etc.
...
.then(ulrs => {
     return web.checkTargetUrls(urls,
        function(singleUrl, pageData) {
        ...
        a chain of promisable functions from db controller,
        which first lookup page id in the db, then its
        puts in the pageId variable and continues with write to db
        ...
}).then(() => {
logger.info('All done captain!');
}).catch(err => {logger.error(err})

pageId随机被上一页/下一页的id覆盖,并保存无效数据。在web中,有多达10个PhantomJ的并发实例在运行,它们在分析页面后调用writer函数。对不起,我的语言,但对我来说,这种情况的一个类比是,如果我有,比如说,某个对象的10个实例,然后它们依赖于一个单例进行编写,这会导致pageId覆盖问题(不知道如何用JS/Node.JS术语正确表达)。

到目前为止,我已经找到了一个解决这个问题的方法,但它很难看,因为它引入了紧密耦合。如果我把writer代码放在一个单独的模块中,然后直接从web控制器内部加载,一切都会很好。但对我来说,这是一个糟糕的设计模式,我宁愿不这样做。

var writer = require('./writer');
function checkTargetUrls(urls, executionId) {
return new Promise(
    function(resolve, reject) {
        let poolSize = config.phantomJs.concurrentInstances;
        let running = 0;
        ....
        a bit of code goes here
        ....
        if (slots != undefined && slots != null && slots.data.length > 0) {
           return writer.write(executionId, singleUrl, slots);
         }
         ...
         more code follows
})
}

我很难找到一个更好的解决方案,在那里我仍然可以传递writer作为checkTargetUrls(urls, writer)函数的参数。有人能给我指明正确的方向吗?或者建议在哪里寻找答案?

我并不完全清楚全局pageId的确切问题,但您可以通过从"web"控制器中公开setWriter函数来减少耦合。

var writer;
module.exports.setWriter = function(_writer) { writer = _writer };

然后在你的index.js顶部附近,类似于:

var web = require('./web');
web.setWriter(require('./writer'));