fs.writefile 仅在节点js的最后一个函数中执行

fs.writefile only execute in last function in node js

我的程序有如下所示的三个函数,

    var userId = req.userId;
    var appId = req.body.appId;

    var main = 'temp/' + userId + '/templates/' + appId + '/css/main.css';

    var color = req.body.color;
    var font = req.body.font;
    var fontSize = req.body.fontSize;

        replaceThemecolor(color);
        replaceFont(font);
        replaceFontSize(fontSize);

    function replaceThemecolor(color) {
        fs.readFile(main, 'utf-8', function (err, data) {
            var regex =/(\.made-easy-themeColor\s*{[^}]*color\s*:\s*)([^\n;}]+)([\s*;}])/;
            var result = data.replace(regex, "" + color + "");
            console.log(color);
            fs.writeFile(main, result, 'utf-8', function (err) {
                if (err) return console.log(err);
            });
        });
    }

    function replaceFont(font)  {
        fs.readFile(main, 'utf-8', function (err, data) {
            var regex =/(\.made-easy-themeFont\s*{[^}]*font-family\s*:\s*)([^\n;}]+)([\s*;}])/;
            var result = data.replace(regex, "" + font + "");
            console.log(font);
            fs.writeFile(main, result, 'utf-8', function (err) {
                if (err) return console.log(err);
            });
                        console.log(result);
        })
    }

    function replaceFontSize(fontSize)  {
        fs.readFile(main, 'utf-8', function (err, data) {
            var regex =/(\.made-easy-themeFontSize\s*{[^}]*font-size\s*:\s*)([^\n;}]+)([\s*;}])/;
            var result1 = data.replace(regex, "" + fontSize + "em" + "");
            console.log(fontSize);
            fs.writeFile(main, result1, 'utf-8', function (err) {
                if (err) return console.log(err);
            });
        });
    }

这里只有最后一个函数一直在执行,当我单独执行它们时它们运行良好,但是当所有函数同时执行时就会出现问题。 fs.writeFile函数有问题吗?我想同时执行这三个功能,有没有办法做到这一点?这里的所有函数在单独执行时都能很好地工作。

您的文件函数是异步的。您不能同时 运行 它们,因为它们会发生冲突并且一个会覆盖另一个的更改。你必须运行一个,然后当它完成时,运行另一个。

或者,更好的是,只读取文件一次,处理所有更改的数据,然后写入一次。


如果你要按顺序 运行 它们,那么你需要将回调传递给每个函数,当它完成时调用,这样你就知道什么时候开始下一个函数。


但是,我认为更好的解决方案是传递一组替换指令,并在文件的一次读写中处理所有这些指令。我将为此编写一个代码示例。

这是一种在一个 read/write 文件中完成所有更新并使用 promises 知道操作何时完成的方法:

function updateFile(filename, replacements) {
    return new Promise(function(resolve, reject) {
        fs.readFile(filename, 'utf-8', function(err, data) {
            if (err) {
                reject(err);
            } else {
                // now cycle through and do all the replacements
                for (var i = 0; i < replacements.length; i++) {
                    data = data.replace(replacements[i].regex, replacements[i].replacer);
                }
                fs.writeFile(filename, data, 'utf-8', function(err) {
                    if (err) {
                        reject(err);
                    } else {
                        resolve();
                    }
                });
            }
        });
    });
}

updateFile(main, [{regex: /(\.made-easy-themeColor\s*{[^}]*color\s*:\s*)([^\n;}]+)([\s*;}])/, replacer: "" + color + ""}, 
                {regex: /(\.made-easy-themeFont\s*{[^}]*font-family\s*:\s*)([^\n;}]+)([\s*;}])/, replacer: "" + font + ""}, 
                {regex: /(\.made-easy-themeFontSize\s*{[^}]*font-size\s*:\s*)([^\n;}]+)([\s*;}])/, replacer: "" + fontSize + "em"}]).then(function() {
                    // update done successfully
                }, function(err) {
                    // error
                });

再做一些工作,您可能也可以只从正则表达式中抽象出关键字,因此您只需要传入关键字,但我会留到以后再说。


这是一个简化版本:

function updateFile(filename, replacements) {
    return new Promise(function(resolve, reject) {
        fs.readFile(filename, 'utf-8', function(err, data) {
            var regex, replaceStr;
            if (err) {
                reject(err);
            } else {
                // now cycle through and do all the replacements
                for (var i = 0; i < replacements.length; i++) {
                    regex = new Regex("(\" + replacements[i].rule + "\s*{[^}]*" + replacements[i].target + "\s*:\s*)([^\n;}]+)([\s*;}])");
                    replaceStr = "" + replacements[i].replacer + "";
                    data = data.replace(regex, replaceStr);
                }
                fs.writeFile(filename, data, 'utf-8', function(err) {
                    if (err) {
                        reject(err);
                    } else {
                        resolve();
                    }
                });
            }
        });
    });
}

updateFile(main, [
        {rule: ".made-easy-themeColor", target: "color", replacer: color}, 
        {rule: ".made-easy-themeFont", target: "font-family", replacer: font}, 
        {rule: ".made-easy-themeFontSize", target: "font-size", replacer: fontSize + "em"} 
    ], function() {
        // update done successfully
    }, function(err) {
        // error
});                

而且,如果您不想知道什么时候完成或者不想 return 出错(我不推荐,但代码更简单)。

function updateFile(filename, replacements) {
    fs.readFile(filename, 'utf-8', function(err, data) {
        var regex, replaceStr;
        if (err) { return; }
        // now cycle through and do all the replacements
        for (var i = 0; i < replacements.length; i++) {
            regex = new Regex("(\" + replacements[i].rule + "\s*{[^}]*" + replacements[i].target + "\s*:\s*)([^\n;}]+)([\s*;}])");
            replaceStr = "" + replacements[i].replacer + "";
            data = data.replace(regex, replaceStr);
        }
        fs.writeFile(filename, data, 'utf-8');
    });
}

updateFile(main, [
        {rule: ".made-easy-themeColor", target: "color", replacer: color}, 
        {rule: ".made-easy-themeFont", target: "font-family", replacer: font}, 
        {rule: ".made-easy-themeFontSize", target: "font-size", replacer: fontSize + "em"} 
    ], function() {
        // update done successfully
    }, function(err) {
        // error
});                

请注意添加更多替换项是多么容易。您只需向传递的数组再添加一行 updateFile().

Node.js 本质上是异步的。因此,您正在快速连续执行三个读取操作,然后尝试写入一个已经文件锁定的文件,或者至少在读取时不包含写入更改。我会使用更像 async 的系列或瀑布方法来解决这个问题。

var async = require("async");
var userId = req.userId;
var appId = req.body.appId;

var main = 'temp/' + userId + '/templates/' + appId + '/css/main.css';

var color = req.body.color;
var font = req.body.font;
var fontSize = req.body.fontSize;

async.series({
    replaceThemecolor: function(callback) {
        fs.readFile(main, 'utf-8', function(err, data) {
            var regex = /(\.made-easy-themeColor\s*{[^}]*color\s*:\s*)([^\n;}]+)([\s*;}])/;
            var result = data.replace(regex, "" + color + "");
            console.log(color);
            fs.writeFile(main, result, 'utf-8', function(err) {
                callback(err);
            });
        });
    },
    replaceFont: function(callback) {
        fs.readFile(main, 'utf-8', function(err, data) {
            var regex = /(\.made-easy-themeFont\s*{[^}]*font-family\s*:\s*)([^\n;}]+)([\s*;}])/;
            var result = data.replace(regex, "" + font + "");
            console.log(font);
            fs.writeFile(main, result, 'utf-8', function(err) {
                callback(err);
            });
        })
    },
    replaceFontSize: function(callback) {
        fs.readFile(main, 'utf-8', function(err, data) {
            var regex = /(\.made-easy-themeFontSize\s*{[^}]*font-size\s*:\s*)([^\n;}]+)([\s*;}])/;
            var result1 = data.replace(regex, "" + fontSize + "em" + "");
            console.log(fontSize);
            fs.writeFile(main, result1, 'utf-8', function(err) {
                callback(err);
            });
        });
    }
}, function(err, results) {
    // results is empty, but now the operation is done.
});