异步回调函数

时间:2020-09-07 05:22:57

标签: node.js

我正在处理的代码块使用fs模块方法createReadStream()读取CSV文件,并且在遇到新的一行数据时会对这些数据进行操作,然后将其发送到数据库在另一种方法中。它执行的操作之一是在每一行代码中哈希密码。为此,我正在使用bcrypt哈希方法,但是由于该方法通常是同步的,因此在将数据发送到数据库之前并不会完成,这不是我想要的。

(非常)我的代码块的结构大致如下:

fs.createReadStream(csvFilePath)
    .on('error', error => console.log("Error"))
    .on('data', data => {
        bcrypt.hash(data.password, 10, (err, hash) => {
            if (err) console.log("Error");
            else data.password = hash;
        });
        dataToUpload.push(data);
    })
    .on('end', () => uploadToDatabase(dataToUpload))

这最终导致密码以完全相同的形式保留而没有任何哈希(因为bcrypt.hash在其余代码块之前未完成)。因此,我决定尝试另一种形式,大致如下:

fs.createReadStream(csvFilePath)
    .on('error', error => console.log("Error"))
    .on('data', data => {
        bcrypt.hash(data.password, 10, (err, hash) => {
            if (err) console.log("Error");
            else {
                data.password = hash;
                dataToUpload.push(data);
            }
        });
    })
    .on('end', () => uploadToDatabase(dataToUpload))

这可以确保在散列完成之前不会将数据推送到数组dataToUpload,但是readStream会继续读取数据,然后才能将数据推送到数组,这意味着不会上传任何内容。

我尝试了async / await的各种实现,如以下两个示例所示:

fs.createReadStream(csvFilePath)
    .on('error', error => console.log("Error"))
    .on('data', async (data) => {
        await bcrypt.hash(data.password, 10, (err, hash) => {
            if (err) console.log("Error");
            else {
                data.password = hash;
                dataToUpload.push(data);
            }
        });
    })
    .on('end', () => uploadToDatabase(dataToUpload))

&&

fs.createReadStream(csvFilePath)
    .on('error', error => console.log("Error"))
    .on('data', data => {
        await bcrypt.hash(data.password, 10);
        dataToUpload.push(data);
    })
    .on('end', () => uploadToDatabase(dataToUpload))

但是在这两种情况下,readStream仍继续读取。我发现了这样一种可能的暂停和恢复读数的方法:

let readCSV = fs.createReadStream(csvFilePath)
readCSV.on('error', error => console.log("Error"))
readCSV.on('data', data => {
    readCSV.pause()
    bcrypt.hash(data.password, 10, (err, hash) => {
        if (err) console.log("Error");
        else {
            data.password = hash;
            dataToUpload.push(data);
            readCSV.resume();
        }
    });
})
readCSV.on('end', () => uploadToDatabase(dataToUpload))

但是数据以某种字节数组的形式出现,而不是我期望的数据吗?

我想知道是否有人知道一种在不增加新库等代码额外代码开销的情况下实现这一目标的方法。

1 个答案:

答案 0 :(得分:0)

您可以利用Promises,并使每个bcrypt.hash成为一个Promise任务,然后将其推送到promises数组。然后,在end事件中,您可以等待所有的承诺解决,然后继续上载到数据库。这样,您就不需要对数据进行两次迭代。

看下面的例子:

const promises = [];
fs.createReadStream(csvFilePath)
    .on('error', error => console.log("Error"))
    .on('data', data => {
        const task = new Promise((resolve, reject) => {
          bcrypt.hash(data.password, 10, (err, hash) => {
              if (err) reject("Error");
              else {
                  data.password = hash;
                  resolve(data);
              }
          });
        });
        promises.push(task);
    })
    .on('end', () => {
      Promise.all(promises)
        .then((hashedDataArray) => {
          uploadToDatabase(hashedDataArray)
        })
        .catch((err) => console.log(err));
    });
相关问题