Node js异步等待函数不会相互等待

时间:2021-06-22 14:06:34

标签: javascript node.js async-await

我有一个项目,该项目具有读取文件并提取其哈希码的功能。在项目中提取这些哈希码后,将一一构建子文件。最后,我想做的是将所有这些哈希码放入一个数组中并创建一个 json 文件。我需要在 IterateFolders() 函数在 readDirectory 函数中运行并完成之后执行此操作。但是console.log在没有等待这个功能的情况下运行在底线,请帮忙。

我的功能如下:


//Calculate build time 
function getBuildTime(start,end) {
    let time = (end - start);
    let buildTime = `${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()} Build time: ${time} ms \n`   
    
    fs.writeFile('build-time.log', buildTime,function (err) { //output log file
        if (err) return console.log(err);
      });
}

//async metaHash calculation from folder path
async function computeMetaHash(folder, inputHash = null) {
    const hash = inputHash ? inputHash : createHash('sha256');
    const info = await fsp.readdir(folder, { withFileTypes: true });
    //construct a string from the modification date, the filename and the filesize
    for (let item of info) {
        const fullPath = path.join(folder, item.name)
        if (item.isFile()) {
            const statInfo = await fsp.stat(fullPath); //stat return all informations about file
            // compute hash string name:size:mtime
            const fileInfo = `${fullPath}:${statInfo.size}:${statInfo.mtimeMs}`;
            hash.update(fileInfo);        
        } else if (item.isDirectory()) {
            // recursively walk sub-folders
            await computeMetaHash(fullPath, hash);
        }
    }
    // if not being called recursively, get the digest and return it as the hash result
    if (!inputHash) {
        return hash.digest('base64');
    }
}


async function iterateFolders(folderPath) {
    folderPath.forEach(function (files) {
        //function takes folder path as inputh
        computeMetaHash(files).then(result => { //call create hash function
        
            console.log({"path":files,"hashCode":result});

        }).then(()=>{ //build fragments 
            //The files is array, so each. files is the folder name. can handle the folder.
            console.log("%s build...", files);
            execSync(`cd ${files} && npm run build`, { encoding: 'utf-8' });  

        }).then(()=>{// Finish timing

            end = new Date().getTime();
            getBuildTime(start,end);  

        }).catch(err => {
            console.log(err);
        });
    }); 

}

async function readDirectory() {

    let files = await readdir(p)
    const folderPath = files.map(function (file) {
        //return file or folder path
        return path.join(p, file);
    }).filter(function (file) {
        //use sync judge method. The file will add next files array if the file is directory, or not. 
        return fs.statSync(file).isDirectory();
    })
    //check hash.json exist or not
    if (fs.existsSync(hashFile)) {
        // path exists
        console.log("File exists: ", hashFile);
        } 
    else 
        {
            //This is the first pipeline, all fragments will build then hash.json will created.
            console.log(hashFile," does NOT exist, build will start and hash.json will created:");
            // Start timing
            start = new Date().getTime();
            iterateFolders(folderPath,files);

            console.log("IT WILL BE LAST ONE ")
            
        }
}
readDirectory();

2 个答案:

答案 0 :(得分:3)

好吧,如果你想等待它的执行,那么你必须使用 await :) 目前它只是 iterateFolders(folderPath,files);,所以你运行它,但你不等待它。

await iterateFolders(folderPath,files);

这是你的第一个问题。然后这个方法运行一些循环并调用一些其他方法。但首先 async-await 需要返回一个承诺(你不这样做)。其次 - 如上面的评论所述,它在 forEach 中不起作用。阅读Using async/await with a forEach loop了解更多详情。

解决这三个问题,你就会成功。

答案 1 :(得分:1)

iterateFolders 函数中,您需要等待 computeMetaHash 调用。为此,您可以使用 for 循环而不是在 folderPath 上调用 forEach 或将 forEach 更改为 map 并使用 Promise.all

使用 for 循环方法(同步):

async function iterateFolders(folderPath) {
    for (let files of folderPath) {
        //function takes folder path as inputh
        await computeMetaHash(files).then(result => { //call create hash function
            console.log({"path":files,"hashCode":result});

        }).then(()=>{ //build fragments 
            //The files is array, so each. files is the folder name. can handle the folder.
            console.log("%s build...", files);
            execSync(`cd ${files} && npm run build`, { encoding: 'utf-8' });  

        }).then(()=>{// Finish timing

            end = new Date().getTime();
            getBuildTime(start,end);  

        }).catch(err => {
            console.log(err);
        });
    }
}

使用 Promise.all 方法(异步):

async function iterateFolders(folderPath) {
    return Promise.all(folderPath.map(function (files) {
        //function takes folder path as inputh
        return computeMetaHash(files).then(result => { //call create hash function
        
            console.log({"path":files,"hashCode":result});

        }).then(()=>{ //build fragments 
            //The files is array, so each. files is the folder name. can handle the folder.
            console.log("%s build...", files);
            execSync(`cd ${files} && npm run build`, { encoding: 'utf-8' });  

        }).then(()=>{// Finish timing

            end = new Date().getTime();
            getBuildTime(start,end);  

        }).catch(err => {
            console.log(err);
        });
    }));
}

如果您愿意,使用 async/await 还可以让您摆脱这两种方法中的 thencatch,我相信这会使其更易于阅读和理解。
以下是使用 Promise.all 方法的示例:

async function iterateFolders(folderPath) {
  return Promise.all(folderPath.map(async (files) => {
      try {
          const result = await computeMetaHash(files);
          console.log({ path: files, hashCode: result });

          // build fragments

          //The files is array, so each. files is the folder name. can handle the folder.
          console.log('%s build...', files);
          execSync(`cd ${files} && npm run build`, { encoding: 'utf-8' });

          
          // Finish timing
          const end = Date.now();
          getBuildTime(start, end);
          
      } catch(err) {
          console.log(err);
      }
  }));
}

您可能还想查看for await... of

注意:您还需要在 iterateFolders 中调用时等待 readDirectory