Node.js json文件被另一个调用覆盖

时间:2014-05-09 18:38:13

标签: node.js express

我正在尝试通过编写配方应用程序来学习Node + Express和Angular。

我在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');
        });
    }); 
};

我遇到的问题是Angular应用程序会触发一系列回调节点的调用以保存每个成分,而无需等待每个成分完成,然后再触发下一个调用,尽管每个调用返回一个成分的id ,只有最后一个成分保存,所以最后一次调用必须覆盖它之前的数据。

我知道我可以改变Angular应用程序在保存下一个成分之前等待响应的方式,但我觉得Node应用程序应该能够支持这样的请求。有没有办法锁定文件或我应采取的其他方法?

1 个答案:

答案 0 :(得分:2)

问题是您正在运行多个请求以同时保存文件。

保存A到达并异步加载文件 - 在此期间保存B到达并在保存A提交更改之前加载。

解决方案是一次只运行其中一个保存请求 - 类似这样(我没有测试过),它按顺序保存一系列保存函数和块:

// 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()
};