使用 Promise.all 为 AWS Node.js 上传创建进度条

Creating a progress bar for AWS Node.js upload using Promise.all

我一直在研究以下代码,试图将我当前的 AWS 上传器减少到几行代码。这段代码效果很好,但我真的需要一个进度指示器来监控上传进度,因为对于较大的文件或文件夹上传,用户不知道需要多长时间。

我是 promise await 的新手,我当前的代码使用回调。

我在这里看到这段代码。

是否可以为每个上传成功的文件回调?这样我就可以得到所有要上传的文件的总长度,并根据该长度输出一个进度。

这是我当前的代码。

let AWS = require("aws-sdk");

const fs = require('fs');

const path = require('path');

const s3 = new AWS.S3();

const params = [];

fs.readdirSync('/Users/dave/Desktop/uploadit').forEach(file => {

    const {
        ext,
        name,
        dir
    } = path.parse(file);

    let fl = name.replace(/[^a-z0-9/]/gi, '_').toLowerCase();

    params.push({ 
        Bucket: 's3b-south-amercia', 
        Key: fl + ext, 
        Body: fs.readFileSync('/Users/dave/Desktop/uploadit/' + file)
    });

});

var total_files = params.length;

// Start function
const start = async function(a, b) {
    
    console.time('test');

    const responses = await Promise.all(
        params.map(param => s3.upload(param).promise())
    );

    console.timeEnd('test');

}

// Call start
start();

// time aws s3 cp /Users/dave/Desktop/uploadit s3://s3b-south-amercia/ --recursive
// AWS CLI 26.295 / 24.684s
// AWS NODE 27.859s / 20.483

我已经针对 AWS cli line cp 命令测试了代码,它们的上传时间相似。

任何帮助或指出如何使用 promise all 实现回调的正确方向将不胜感激,我不确定 promise all 并非旨在执行此操作。

谢谢

工作代码感谢@nobody ;)

let AWS = require("aws-sdk");

const fs = require('fs');

const path = require('path');

const s3 = new AWS.S3();

const params = [];

fs.readdirSync('/Users/dave/Desktop/uploadit').forEach(file => {

    const {
        ext,
        name,
        dir
    } = path.parse(file);

    let fl = name.replace(/[^a-z0-9/]/gi, '_').toLowerCase();

    params.push({ 
        Bucket: 's3b-south-amercia', 
        Key: fl + ext, 
        Body: fs.readFileSync('/Users/dave/Desktop/uploadit/' + file)
    });

});

var progress = 1;

var total_files = params.length;

console.log('total_files', total_files);

const onProgress = async promise => {

    const result = await promise;

    console.log(progress / total_files * 100 + '%');

    progress++;
    
    return result;

};

// Start function
const start = async function(a, b) {
    
    console.time('test');

    const responses = await Promise.all(
        params.map(param => onProgress(s3.upload(param).promise()))
    );
    /*const responses = await Promise.all(
        params.map(param => s3.upload(param).promise())
    );*/

    console.timeEnd('test');

}

// Call start
start();

// time aws s3 cp /Users/dave/Desktop/uploadit s3://s3b-south-amercia/ --recursive
// AWS CLI 26.295 / 24.684s
// AWS NODE 27.859s / 20.483

更新:

只是通知任何使用此代码的人,当您 运行 在包含大量文件的文件夹中使用此代码时,您几乎肯定会遇到此错误。

RequestTimeTooSkewed: 请求时间与当前时间相差太大

我在这里创建了一个工单和一个解决方法。

https://github.com/aws/aws-sdk-js/issues/3757

但希望 SDK 很快就会得到修复。

你可以用你自己的函数包装 s3.upload,只要 returns 原始响应你就会有一个钩子进入 Promise.all 中的每个承诺。

const onDone = async promise => {
  const result = await promise;
  console.log("File upload complete");
  // Or add +1 to some variable to calculate percentage of completed uploads
  return result;
};

const responses = await Promise.all(
  params.map(param => onDone(s3.upload(param).promise()))
);

这是一个使用自定义承诺库的示例,该库支持开箱即用的高级进度捕获(并发限制只是为了演示而添加): Live sandbox

import { CPromise } from "c-promise2";

(async () => {
  const results = await CPromise.all(
    [
      "filename1.txt",
      "filename2.txt",
      "filename3.txt",
      "filename4.txt",
      "filename5.txt",
      "filename6.txt",
      "filename7.txt"
    ],
    {
      async mapper(filename) {
        console.log(`load and push file [${filename}]`);
        // your async code here to upload a single file
        return CPromise.delay(1000, `operation result for [${filename}]`);
      },
      concurrency: 2
    }
  ).progress((p) => {
    console.warn(`Uploading: ${(p * 100).toFixed(1)}%`);
  });

  console.log(results);
})();