I'm playing around trying to learn Node+Express and Angular by writing a recipe application.
我正在尝试通过编写配方应用程序来学习Node + Express和Angular。
I'm storing an array of recipes and an array of ingredients in a json file as my data store and I have a simple saveMeal() and saveIngredient() method in Node like this:
我在json文件中存储了一系列食谱和一系列成分作为我的数据存储,我在Node中有一个简单的saveMeal()和saveIngredient()方法,如下所示:
exports.saveIngredient = function(req, res) {
var ing = req.body;
console.log('Saving Ingredient: ' + JSON.stringify(ing, null, 4));
fs.readFile('./data/data.json', 'utf-8', function (error, data) {
var mData = JSON.parse(data);
ing.id = generateId(ing.name, mData.ingredients);
mData.ingredients.push(ing);
fs.writeFile('./data/data.json', JSON.stringify(mData, null, 4), function(err) {
res.writeHead(200, { 'Content-Type': 'text/json' });
res.end(ing.id, 'utf-8');
});
});
};
The problem I'm having is that the Angular app fires off a series of calls back to Node to save each ingredient without waiting for each one to finish before firing off the next call and although each call returns an id for the ingredient, only the last ingredient saves, so the last call must be overwriting the data before it.
我遇到的问题是Angular应用程序触发一系列回调节点的调用以保存每个成分而不等待每个成分完成然后触发下一个调用,尽管每个调用返回一个成分的id,只有最后一个成分保存,所以最后一个调用必须覆盖它之前的数据。
I know I could change the way the Angular app works to wait for a response before saving the next ingredient, but I kinda feel the Node app should be able to support requests like this. Is there a way to lock the file or a different approach I should be taking?
我知道我可以改变Angular应用程序在保存下一个成分之前等待响应的方式,但我觉得Node应用程序应该能够支持这样的请求。有没有办法锁定文件或我应采取的不同方法?
1 个解决方案
#1
2
The problem is that you are running multiple requests to save the file at the same time.
问题是您正在运行多个请求以同时保存文件。
Save A arrives and async loads the file - during which time Save B arrives and loads before Save A has committed its change.
保存A到达并异步加载文件 - 在此期间,保存B到达并在保存A提交更改之前加载。
The solution is to run only one of these save requests at a time - something like this (which I've not tested) that keeps an array of save functions and chunks through them in sequence of arriving:
解决方案是一次只运行其中一个保存请求 - 类似这样(我没有测试过),它按顺序保存一组保存函数和块:
// an array of functions in the queue
var fnBuffer = []
// are we currently running a function in the queue
var running = false
// run the queue one at a time - on finish run again
function runSave(){
if(running) return
running = true
var nextfn = fnBuffer.shift()
if(!nextfn) return
nextfn(function(){
running = false
runSave()
})
}
exports.saveIngredient = function(req, res) {
// push the function onto the queue
fnBuffer.push(function(callback){
// this is the original code - the only extra is the callback
var ing = req.body;
console.log('Saving Ingredient: ' + JSON.stringify(ing, null, 4));
fs.readFile('./data/data.json', 'utf-8', function (error, data) {
var mData = JSON.parse(data);
ing.id = generateId(ing.name, mData.ingredients);
mData.ingredients.push(ing);
fs.writeFile('./data/data.json', JSON.stringify(mData, null, 4), function(err) {
res.writeHead(200, { 'Content-Type': 'text/json' });
res.end(ing.id, 'utf-8');
// running this callback tells the queue to run the next function
callback()
});
});
})
// trigger the queue
runSave()
};
#1
2
The problem is that you are running multiple requests to save the file at the same time.
问题是您正在运行多个请求以同时保存文件。
Save A arrives and async loads the file - during which time Save B arrives and loads before Save A has committed its change.
保存A到达并异步加载文件 - 在此期间,保存B到达并在保存A提交更改之前加载。
The solution is to run only one of these save requests at a time - something like this (which I've not tested) that keeps an array of save functions and chunks through them in sequence of arriving:
解决方案是一次只运行其中一个保存请求 - 类似这样(我没有测试过),它按顺序保存一组保存函数和块:
// an array of functions in the queue
var fnBuffer = []
// are we currently running a function in the queue
var running = false
// run the queue one at a time - on finish run again
function runSave(){
if(running) return
running = true
var nextfn = fnBuffer.shift()
if(!nextfn) return
nextfn(function(){
running = false
runSave()
})
}
exports.saveIngredient = function(req, res) {
// push the function onto the queue
fnBuffer.push(function(callback){
// this is the original code - the only extra is the callback
var ing = req.body;
console.log('Saving Ingredient: ' + JSON.stringify(ing, null, 4));
fs.readFile('./data/data.json', 'utf-8', function (error, data) {
var mData = JSON.parse(data);
ing.id = generateId(ing.name, mData.ingredients);
mData.ingredients.push(ing);
fs.writeFile('./data/data.json', JSON.stringify(mData, null, 4), function(err) {
res.writeHead(200, { 'Content-Type': 'text/json' });
res.end(ing.id, 'utf-8');
// running this callback tells the queue to run the next function
callback()
});
});
})
// trigger the queue
runSave()
};