Javascript 在heavy Node.js应用程序上保持节点不返回值
我有一个沉重的节点应用程序,我使用节点持久保存数据到本地数据库 在某一特定步骤中,我有以下几点:Javascript 在heavy Node.js应用程序上保持节点不返回值,javascript,node.js,async-await,node-persist,Javascript,Node.js,Async Await,Node Persist,我有一个沉重的节点应用程序,我使用节点持久保存数据到本地数据库 在某一特定步骤中,我有以下几点: const localdb = require('node-persist') const storage = localdb.create({ttl: true}) await storage.init() function game(socket, log, opts) { // [...] async function scoreHandler(data) {
const localdb = require('node-persist')
const storage = localdb.create({ttl: true})
await storage.init()
function game(socket, log, opts) {
// [...]
async function scoreHandler(data) {
if (data.scoreUp) {
await storage.setItem(data.sid,data.uid)
} else if (data.scoreDown) {
try {
let uid = await storage.getItem(data.sid);
if (typeof uid == 'undefined') {
return;
}
console.log(uid);
} catch (e) {
return;
}
}
}
}
这段代码在长函数中有点深。一切都很简单。但有两个问题:
uid通常是未定义的。我的猜测是该文件尚未保存,因此当我尝试获取该文件上的项时,它具有未定义的值。
即使uid=='undefined',console.loguid仍然抛出许多未定义的错误。我不明白为什么,因为我回来了。
代码就是这样。这个if可能每秒调用15-20次。控制台上没有其他可能抛出未定义的代码,也没有任何写入db的代码
为什么会这样?我该怎么做才能妥善处理呢
编辑1
我明白了第二点。我忘了放打字机了
编辑2
我根据请求添加了init
如果我删除try…catch,我经常会出现以下错误:
(node:9608) UnhandledPromiseRejectionWarning: Error: [node-persist][readFile] ... does not look like a valid storage file!
at fs.readFile (...node-persist/src/local-storage.js:277:66)
at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:511:3)
因此,我猜测getItem正在尝试读取setItem尚未完成写入的文件。看来node persist无法处理并发读写操作
如果在setItem进行过程中调用getItem,则会引发此错误
唯一的解决方案是由库修复,或者确保在调用setItem时从不调用getItem
我的建议是将与该存储相关的所有符号包装到自己的类中。以便以后可以轻松地用另一个库替换它
我填了一个问题:
节点persist似乎不能可靠地处理并发读写
如果在setItem进行过程中调用getItem,则会引发此错误
唯一的解决方案是由库修复,或者确保在调用setItem时从不调用getItem
我的建议是将与该存储相关的所有符号包装到自己的类中。以便以后可以轻松地用另一个库替换它
我填了一个问题:
为了补充@t.niese所说的内容,库基本上没有提供并发性。解决方案之一是序列化对库的调用。下面是对库的所有调用进行序列化的代码示例 此外,给定的库会将每个键值对写入单个文件。我认为对每个键的调用进行序列化将提供更好的吞吐量 话虽如此,这件事应该在图书馆处理 注释和取消注释节点持久化存储的选择或节点持久化周围的包装
const localdb = require('node-persist')
const when = require('when');
class QueuedStorage {
constructor() {
this.storage = localdb.create({ ttl: true, logging: false})
}
async init() {
await this.storage.init();
}
async getItem(key) {
this.current = when(this.current,
() => { return this.storage.getItem(key)},
() => { return this.storage.getItem(key)});
return this.current;
}
async setItem(key, value) {
this.current = when(this.current,
() => { return this.storage.setItem(key,value)},
() => { return this.storage.setItem(key,value)});
return this.current;
}
};
//const storage = new QueuedStorage();
const storage = localdb.create({ ttl: true, logging: true })
async function main () {
await storage.init()
try {
const key = 'DSF-AS-558-DDDF';
const fs = new Array(10000)
.fill(0)
.map((e,i) => function() {
if(i%2) return storage.getItem(key)
else return storage.setItem(key,i)}());
Promise.all(fs).then(values => console.log(values));
} catch (err) {
console.error(err)
}
}
main().catch(err => {
console.error(err)
})
为了补充@t.niese所说的内容,库基本上没有提供并发性。解决方案之一是序列化对库的调用。下面是对库的所有调用进行序列化的代码示例 此外,给定的库会将每个键值对写入单个文件。我认为对每个键的调用进行序列化将提供更好的吞吐量 话虽如此,这件事应该在图书馆处理 注释和取消注释节点持久化存储的选择或节点持久化周围的包装
const localdb = require('node-persist')
const when = require('when');
class QueuedStorage {
constructor() {
this.storage = localdb.create({ ttl: true, logging: false})
}
async init() {
await this.storage.init();
}
async getItem(key) {
this.current = when(this.current,
() => { return this.storage.getItem(key)},
() => { return this.storage.getItem(key)});
return this.current;
}
async setItem(key, value) {
this.current = when(this.current,
() => { return this.storage.setItem(key,value)},
() => { return this.storage.setItem(key,value)});
return this.current;
}
};
//const storage = new QueuedStorage();
const storage = localdb.create({ ttl: true, logging: true })
async function main () {
await storage.init()
try {
const key = 'DSF-AS-558-DDDF';
const fs = new Array(10000)
.fill(0)
.map((e,i) => function() {
if(i%2) return storage.getItem(key)
else return storage.setItem(key,i)}());
Promise.all(fs).then(values => console.log(values));
} catch (err) {
console.error(err)
}
}
main().catch(err => {
console.error(err)
})
您还可以发布节点的init调用吗?此外,如果可能,请添加更多上下文代码,因为问题可能不在这段代码中。@Biswanath I添加了一段代码和一条错误消息。我认为问题在于我试图读取一个上一个setItem尚未完成编写的文件。它包含在一个函数中显示的全部代码,包括const storage=localdb.create{ttl:true}和wait storage。init@t.niese很抱歉,我想在这里保持代码简短,并且没有包含函数声明。现在有了。那是你唯一使用存储的地方吗?您是否可以调用scoreHandler multible time,即使scoreHandler尚未完成?如果在setItem进行过程中调用getItem,则会出现错误消息。而UnhandledPromisejectionWarning表示您没有正确处理scoreHandler的结果/预期或某个callin祖先。您是否也可以发布节点的初始化调用?此外,如果可能,请添加更多上下文代码,因为问题可能不在这段代码中。@Biswanath I添加了一段代码和一条错误消息。我认为问题在于我试图读取一个上一个setItem尚未完成编写的文件。它包含在一个函数中显示的全部代码,包括const storage=localdb.create{ttl:true}和wait storage。init@t.niese很抱歉,我想在这里保持代码简短,并且没有包含函数声明。现在有了。那是你唯一使用存储的地方吗?您是否可以调用scoreHandler multible time,即使scoreHandler尚未完成?如果在setItem进行过程中调用getItem,则会出现错误消息。嗯 AndLedPromisejectionWarning表示您未正确处理scoreHandler的结果/预期或某个callin祖先。