异步计数总计

时间:2018-01-09 21:31:27

标签: node.js loops asynchronous gulp

我有一个 gulp 任务,它循环遍历一组文件并验证每个文件。最后,我想报告有效文件的总数。

const fs = require('fs')
const path = require('path')
const gulp = require('gulp')

gulp.task('validate', function (callback) {
  function validate(json) { /*...*/ }
  let files = ['file1.json', 'file2.json', 'file3.json']
  let count = 0

  files.forEach(function (file) {
    fs.readFile(path.join(__dirname, file), 'utf8', function (err, data) {
      let is_valid = validate(JSON.parse(data))
      if (!is_valid) {
        console.error(`Invalid! ${file}`)
      } else {
        console.log(`Valid: ${file}`)
        count++
      }
    })
  })

  console.log(`Total valid files: ${count}`)
})

运行时,我的控制台会报告:

Total valid files: 0
Valid schema: file1.json
Valid schema: file2.json
Valid schema: file3.json

由于fs.readFile()的异步性质,我怀疑在读取文件之前会报告计数。当我尝试在调用 .forEach()之前记录总计数时,我得到相同的结果(如预期的那样)。如何在异步函数后记录全局变量?

注意:我知道gulp约定是将callback参数传递给gulp任务,但是gulp使用只能传递Error的{​​{3}}来调用此任务。我可以以某种方式创建自己的自定义回调函数,我可以传递给count吗?

1 个答案:

答案 0 :(得分:0)

问题在于'fs'库是旧的并且仅使用回调。

我建议的解决方案是宣传fs.readFile()方法并在数组和promise.all中添加这些promises。

侧节点:使用异步函数时使用forof而不是forEach。

const { promisify } = require('util');
const fs = require('fs');
const readFileAsync = promisify(fs.readFile);

const path = require('path');

let files = ['file1.json', 'file2.json', 'file3.json'];
let count = 0
let tasks = [];

function validate(json) { /*...*/ }

for (let file of files) {
    tasks.push(readFileAsync(path.join(__dirname, file), 'utf8')
        .then(data => {
            let is_valid = validate(JSON.parse(data))
            if (!is_valid) {
                console.error(`Invalid! ${file}`)
            } else {
                console.log(`Valid: ${file}`)
                count++
            }
        })
        .catch(err => console.log(err))
    );
}

Promise.all(tasks)
    .then(res => console.log(`Total valid files: ${count}`))
    .catch(err => console.log(err));