【问题标题】:while in promise ( fs readstream )在承诺期间(fs readstream)
【发布时间】:2020-01-29 13:17:43
【问题描述】:

我制作了一个自动上传备份文件的脚本(在 Backblaze 上)...

制作一个将完整文件加载到const 的脚本,拆分字符串并在文件大小增加(从 1 到超过 3gb)时上传每个部分,我的脚本崩溃了。

我尝试完全异步重写脚本。

我写这个:

async getFileInfoAndUploadPart(path, sizeChunk = 1024) {
    const info = {
      sha1: null,
      size: 0,
      partNumber: 0,
      partSha1: {},
    };
    return new Promise(resolve => {
      const shasumGlobal = crypto.createHash('sha1');
      console.log(path, sizeChunk);
      const input = fs.createReadStream(path);
      input.on('readable', () => {
        console.log('1');
        let chunk;
        while ((chunk = input.read(sizeChunk)) !== null) {
          console.log('2');
          const tempShasum = crypto.createHash('sha1');
          shasumGlobal.update(chunk);
          tempShasum.update(chunk);
          info.partNumber += 1;
          info.partSha1[info.partNumber] = tempShasum.digest('hex');
        }
        console.log('3');
        info.sha1 = shasumGlobal.digest('hex');
        resolve(info);
      });
    });
  }

但承诺在while 之前解决:/ 在返回我的承诺之前完成此操作的正确方法是什么?

(我打算在这个过程中调用一个异步函数来上传每个部分)

编辑

最后我使用了这个方法:

    async getFileInfoAndUploadPart(path, sizeChunk = 1024, fileId = 'xxx') {
    return new Promise(resolve => {
      const info = {
        fileId: fileId,
        sha1: null,
        size: 0,
        partNumber: 0,
        partSha1: {},
      };
      const input = fs.createReadStream(path, { highWaterMark: sizeChunk });
      const shasumGlobal = crypto.createHash('sha1');

      input.on('data', async dataChunk => {
        const shasumPart = await crypto.createHash('sha1');
        await shasumPart.update(dataChunk);
        await shasumGlobal.update(dataChunk);

        info.partNumber += 1;
        info.partSha1[info.partNumber] = shasumPart.digest('hex');
      });

      input.on('end', () => {
        info.sha1 = shasumGlobal.digest('hex');
        resolve(info);
      });
    });
  }

编辑 2:

上面的代码运行不好……

首先,您需要在播放数据时暂停流,并在可以处理下一部分时恢复流...

第二个错误: 如果您使用 10 oct 文件尝试此代码,并使用 5 oct 块...

你第一次触发“数据”事件 => 好的

您第二次触发“数据”事件 => 好的

您触发了“结束”事件 => 好的 ...

但是如果你想将流分成 3 部分( Math.ceil(fileSize/chunkSize) => 4 + 4 + 2 ,只有最后一部分需要更短)

你第一次触发“数据”事件 => 好的

您第二次触发“数据”事件 => 好的

您第三次触发了“数据”事件,但是 您到达流的末尾,因此您在 同时...

只有在我的“数据”逻辑完成后,我才找到触发“结束”事件的任何解决方案...

所以我想我预先计算了块的数量,并在我在最后一个块上时在“数据”事件中实现我的“结束”逻辑......

【问题讨论】:

  • 你的承诺在 while 循环结束之前没有解决。可能存在您的代码在承诺回调中失败的情况,因此承诺可能会拒绝,而不是解决。尝试将.catch(err => console.log(err)) 添加到getFileInfoAndUploadPart 函数返回的结果中并检查错误是什么
  • 脚本崩溃是因为我在shasumGlobal.digest('hex'); 之后调用了shasumGlobal.update(chunk);(并且在我的控制台中我看到了13,以及我的函数的返回......然后崩溃了而...。(永远看不到2 ...)
  • 我们支持在 Node 中直接使用异步迭代器来迭代流,请考虑将其与 for await 一起使用

标签: javascript node.js promise async-await fs


【解决方案1】:
async getFileInfoAndUploadPart(path, sizeChunk = 1024, fileId = 'xxx') {
    return new Promise(resolve => {
      const stats = fs.statSync(path);
      const info = {
        fileId: fileId,
        sha1: null,
        size: 0,
        partNumber: 0,
        partNumberTheoretical: Math.ceil(stats.size/sizeChunk),
        partSha1: {},
      };

      const input = fs.createReadStream(path, { highWaterMark: sizeChunk });
      const shasumGlobal = crypto.createHash('sha1');

      input.on('data', async dataChunk => {
        input.pause();
        const shasumPart = crypto.createHash('sha1');
        shasumPart.update(dataChunk);
        shasumGlobal.update(dataChunk);
        info.partNumber += 1;
        info.partSha1[info.partNumber] = shasumPart.digest('hex');

        // force passe copy of info obj.
        // await this.uploadWithRetry(dataChunk, { ...info }, parameters.getConfig('maxRetry'), parameters.getConfig('waitBeforeRetry'));

        await this.debug().then(() => {
          console.log({ ... info });
        });
        input.resume();

        if (info.partNumber === info.partNumberTheoretical) {
          console.log('end');
          info.sha1 = shasumGlobal.digest('hex');
          resolve(info);
        }
      });
    });
  }

PS:调试是这个功能

async debug(time = 1000) {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve();
      }, time);
    });
  };

【讨论】:

    猜你喜欢
    • 2013-10-26
    • 1970-01-01
    • 2013-06-22
    • 2012-09-19
    • 2017-04-26
    • 1970-01-01
    • 1970-01-01
    • 2021-08-11
    • 2021-10-29
    相关资源
    最近更新 更多