【问题标题】:File creation issues on node节点上的文件创建问题
【发布时间】:2018-11-03 18:25:54
【问题描述】:

我在使用 node.js 生成文件时遇到问题。这些文件不按顺序显示,并且在创建它们的循环完成后,我的自动 git 提交就乱了套。有人能帮助我吗! github 仓库:https://github.com/wendellmva/cli3

class Generator {
    constructor(){
        this.root = resolve(__dirname, 'generated');
    }   

    clean(done){
        if(fs.existsSync(this.root)){
            trash(this.root).then(done);
        } else {
            done();
        }
    }

    execute(){
        this.init()
        for(let i=0; i<10; ++i) {
            const file = resolve(this.root, `file${i}.txt`);
            fs.writeFile(file, 'Hello world', (err)=> {
                if(err) console.error(err);
                console.info('CREATE ', file);
                if(fs.existsSync(file)) this.add(file);
                if(i==9) this.commit();
            });
        }

    }

    init(){
        shelljs.exec(`mkdir ${this.root} && cd ${this.root} && git init`);
    }
    add(file){
        shelljs.exec(`cd ${this.root} && git add ${file}`);
    }
    commit(){
        shelljs.exec(`cd ${this.root} && git commit -m "chore: initial commit"`);
    }
}

const generator = new Generator();

generator.clean(()=>{
    generator.execute();
});

问题 1:提交在执行完成之前开始 导致空提交

问题 2:当生成的文件存在时,在清理完成之前开始执行 导致文件已存在错误 ===> 已解决

问题 3:文件是乱序创建的

Initialized empty Git repository in D:/@cardstrip/cli3/generated/.git/
CREATE  D:\@cardstrip\cli3\generated\file2.txt
CREATE  D:\@cardstrip\cli3\generated\file3.txt
CREATE  D:\@cardstrip\cli3\generated\file0.txt
CREATE  D:\@cardstrip\cli3\generated\file1.txt
CREATE  D:\@cardstrip\cli3\generated\file4.txt
CREATE  D:\@cardstrip\cli3\generated\file5.txt
CREATE  D:\@cardstrip\cli3\generated\file7.txt
CREATE  D:\@cardstrip\cli3\generated\file9.txt
[master (root-commit) 3442284] chore: initial commit
8 files changed, 8 insertions(+)
create mode 100644 file0.txt
create mode 100644 file1.txt
create mode 100644 file2.txt
create mode 100644 file3.txt
create mode 100644 file4.txt
create mode 100644 file5.txt
create mode 100644 file7.txt
create mode 100644 file9.txt
CREATE  D:\@cardstrip\cli3\generated\file6.txt
CREATE  D:\@cardstrip\cli3\generated\file8.txt

【问题讨论】:

标签: javascript node.js


【解决方案1】:

fs.writeFilechild_process.exec 都是异步的,您不会等到操作结束,这就是为什么您的代码没有按照您的预期执行。

我们可以使用util.promisifywriteFileexec 转换为基于Promise 的API,并使用async/await 以正确的顺序执行操作。

const { promisify } = require('util');
const childProcess = require('child_process');
const fs = require('fs');

const writeFile = promisify(fs.readFile);
const exec = promisify(childProcess.exec);


class Generator {
    constructor(){
        this.root = resolve(__dirname, 'generated');
    }   

    async execute() {
        await this.init();

        for(let i=0; i < 10; ++i) {
            const file = resolve(this.root, `file${i}.txt`);

            await writeFile(file, 'Hello world');

            // No need to check if it exists, if it wasn't created writeFile rejects            
            console.info('CREATE ', file);

            await this.add(file);

        }

        return this.commit();
    }

    init(){
        return exec(`mkdir ${this.root} && cd ${this.root} && git init`);
    }

    add(file){
        return exec(`cd ${this.root} && git add ${file}`);
    }

    commit(){
        return exec(`cd ${this.root} && git commit -m "chore: initial commit"`);
    }
}

现在做的时候:

new Generator()
   .execute()
   .then(() => console.log('Commited!')
   .catch(err => console.error(err));

您将按顺序创建和添加文件,然后提交更改。

【讨论】:

  • shelljs.exec 的文档声明它是同步的,除非指定或给出回调
  • @PierreC。 OP 从未指定他使用第三方,所以我假设正在使用childProcess.exec,他没有理由为简单的.exec 添加第三方。在我的回答中,我声明 childProcess.exec 是异步的,确实如此。
  • 确实是这样,但是由于 OP 不使用它,所以回答这个问题是非常不相关的。我可以提出的另一点是 OP 似乎还不太了解回调。在他的代码中引入 promises 和 await/async 可能太多了(即使它很有趣)。
  • 他从不声明他使用的是 shelljs lib,我可以这样做:const shelljs = require('child_process'),如果问题中没有信息,我假设他使用的是本机 API。 async/await 比回调更容易,所以是的,我不认为它太多,而且比使用同步 API 更好,这就是你正在使用的。
  • 我还有一个带有 await/async 的分支,我对其进行了修改。我确实在使用 shelljs,因为它连接了标准输出。我将我的 writefile 和 shelljs.exec 包装在 util 的 promisify 中,这一切都按预期神奇地工作了。非常感谢!
【解决方案2】:

您正在循环中使用fs.writeFile 的异步版本,这意味着您不知道数据写入磁盘的顺序,并且循环不会等待该异步函数的每次调用继续。

你必须想办法知道最后一个文件何时被写入。一种方法是使用fs.writeFile 函数的同步版本,即fs.writeFileSync

execute(){
    this.init();

    for(let i=0; i<10; ++i) {
        const file = resolve(this.root, `file${i}.txt`);
        try {
            fs.writeFileSync(file, 'Hello world');
            console.info('CREATE ', file);

            if(fs.existsSync(file)) this.add(file);
        } catch (err) {
            console.error(err);
        }
    }
    this.commit();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-20
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-16
    • 2018-07-29
    相关资源
    最近更新 更多