【问题标题】:Javascript, uploading several files within an Array.reduce with Promises, how?Javascript,使用 Promises 在 Array.reduce 中上传多个文件,如何?
【发布时间】:2016-12-13 19:32:42
【问题描述】:

Javascript, spliced FileReader for large files with Promises, how? 演变而来,它向我展示了 Promise 如何也可以解析函数,现在我被困在相同但在 Array.reduce 函数中。

目标是我想在数组中上传一个文件(已经上传),其中每个数组项(一个文件)按顺序上传(即通过承诺控制)。

然后,我知道答案不知何故在 http://www.html5rocks.com/en/tutorials/es6/promises/?redirect_from_locale=es 中,但我不明白如何将其应用于此处。我的数组不是一个承诺数组,是一个文件数组。好吧,整个事情对我来说仍然是模糊的。

这是我的代码,如果我能看到einconsole.log 消息,它将起作用:

return myArray.reduce(function(previous, current) {
    var BYTES_PER_CHUNK = 100000;
    var start = 0;
    var temp_end = start + BYTES_PER_CHUNK;
    var end = parseInt(current.size);
    if (temp_end > end) temp_end = end;
    var content = ''; // to be filled by the content of the file
    var uploading_file = current;
    Promise.resolve().then(function() {
        return upload();
    })
    .then(function(content){
        // do stuff with the content
        Promise.resolve();
    });
},0)  // I add the 0 in case myArray has only 1 item
//},Promise.resolve()) goes here?

.then(function(){
    console.log('ein') // this I never see
});

function upload() {
  if (start < end) {
    return new Promise(function(resolve){
      var chunk = uploading_file.slice(start, temp_end);
      var reader = new FileReader();
      reader.readAsArrayBuffer(chunk);
      reader.onload = function(e) {
        if (e.target.readyState == 2) {
          content += new TextDecoder("utf-8").decode(e.target.result);
          start = temp_end;
          temp_end = start + BYTES_PER_CHUNK;
          if (temp_end > end) temp_end = end;
          resolve(upload());
        }
      }
    });
  } else {
    uploading_file = null;
    return Promise.resolve(content);
  }
}
  • 经过几次cmet后更新,现在好像可以了……还不确定

    var uploading_file, start, temp_end, end, content; var BYTES_PER_CHUNK = 100000;

    myArray.reduce(function(previous, current) { 返回上一个 .then(函数(){ BYTES_PER_CHUNK = 100000; 开始 = 0; temp_end = 开始 + BYTES_PER_CHUNK; end = parseInt(current.size); 如果(临时结束>结束)临时结束=结束; 内容=''; uploading_file = 当前;

    upload()
    .then(function(content){
        // do stuff with "content"
        console.log('here')
        return Promise.resolve();
    });
    

    }); },Promise.resolve()) .then(函数(){ console.log('ein'); });

    函数上传(){ 如果(开始结束)临时结束=结束; 解决(上传()); } } }); } 别的 { 上传文件=空; 返回 Promise.resolve(内容); } }

  • 改进的代码,似乎可以工作,也许更容易阅读?

        var start, temp_end, end;
        var BYTES_PER_CHUNK = 100000;
    
        myArray.reduce(function(previous, current) {
            return previous
            .then(function() {
                start = 0;
                temp_end = start + BYTES_PER_CHUNK;
                end = parseInt(current.size);
                if (temp_end > end) temp_end = end;
                current.data = '';
    
                return upload(current)
                .then(function(){
                    // do other stuff
                    return Promise.resolve();
                });
            });
        },Promise.resolve())
        .then(function(){
          // do other stuff
        });
    
        function upload(current) {
            if (start < end) {
                return new Promise(function(resolve){
                    var chunk = current.slice(start, temp_end);
                    var reader = new FileReader();
                    reader.readAsText(chunk);
                    reader.onload = function(e) {
                        if (e.target.readyState == 2) {
                            current.data += e.target.result;
                            start = temp_end;
                            temp_end = start + BYTES_PER_CHUNK;
                            if (temp_end > end) temp_end = end;
                            resolve(upload(current));
                        }
                    }
                });
            } else {
                return Promise.resolve();
            }
        }
    

【问题讨论】:

  • 如果您甚至从不参考 previous 参数,那么使用 Array reduce 的意义何在 - 您基本上是在使用带有额外开销的 forEach ...
  • 你杀了我@TJCrowder - 现在我需要知道在基于数组将异步任务链接在一起时当前的最佳实践是什么......不需要详细信息,只需一个提示即可: p
  • @T.J.Crowder,没有冒犯,但你能扩大一点吗?除了 Array.reduce 之外,其余的代码错了吗?当必须将这些文件拼接成块时,我找不到另一种方法来进行顺序文件上传。你会怎么做?
  • @JaromandaX,你说得对,我的印象是我必须使用 Array.reduce 进行顺序上传,也许我必须使用它,但我在这里做错了
  • @Gerard:有几件事跳出来:1.Promise.resolve().then(function() { return upload(); }) 基本上只是upload(),因为upload returns 一个承诺。 2.Promise.resolve();不使用时返回值是空操作。

标签: javascript promise filereader chain array-reduce


【解决方案1】:

你非常接近!您需要使用之前的值;这应该是一个承诺。将reduce的初始值设置为Promise.resolve()。然后在reduce函数内部,而不是Promise.resolve().then(...)。你应该有类似的东西:

return previous
  .then(function() { return upload(current); })
  .then(function() { /* do stuff */ });

您在此处return 很重要。下次调用 reduce 函数时,这将变为 previous


upload 函数存在很多问题。 最大的问题是你传递变量的方式使它很难阅读:)(而且容易出错!)

如果您只阅读文本文件,请改用readAsText。请注意,我已将其重命名为 readFile,因为这是一个更准确的名称。

// returns a promise with the file contents
function readFile(file) {
    return new Promise(function (resolve) {
        var reader = new FileReader();
        reader.onload = function(e) {
            resolve(e.target.result);
        };
        reader.readAsText(file);
    };
}

那么你的 reduce 就是:

files.reduce(function(previous, file) {
    return previous
      .then(function() { return readFile(file); })
      .then(function(contents) {
          // do stuff
      });
}, Promise.resolve());

不过,upload_file 变量存在一个大错误。该变量在 reduce 函数的范围内是本地的,所以它只会在 undefined 内部 upload。将其作为参数传递:

function upload(upload_file) { ... }

关于var 的旁注。这就是为什么即使你在 reduce 函数中设置了 upload_filevar,它仍然是在为 upload 调用该函数之前的任何内容:

var a = 3;

function foo() {
  var a = 4;
  console.log(a); // 4
}

foo();
console.log(a); // 3

【讨论】:

  • 该链接很有用,但如果您更清楚地显示它适合 OP 代码的位置以及您是 OP 代码的哪些部分,它会非常更多有用删除。
  • 主要是想粘贴链接,因为我认为它非常适合这种情况。实际上,减少/承诺的 OP 使用非常接近,但是上传非常糟糕,现在我看看它。该代码将导致很多问题;发布得太快了。
  • @cdrini 非常感谢,正在处理更新的代码,但仍然无法正常工作。关于 upload_file,这是在 Array.reduce 之前定义的,因此范围应该没问题(我在使代码适应问题时犯了错误)。但是,我确实认为我应该通过变量传递它,但在此之前我想修复/理解这个承诺障碍
  • @Gerard 你的承诺几乎是完美的,这是我仍在努力解决的上传问题:) 我假设upload 返回了一个承诺,该承诺在文件完全上传后解决,但是内部和外部都使用变量使代码难以阅读。如果在reduce之前定义,不要使用var;这仅在函数内定义它。
  • @cdrini 我已经更改了“全局”变量的使用,用于发送给函数 (EDIT2) 的变量,希望现在可以更清楚地阅读?但是为什么不使用var?我不应该总是(?)
猜你喜欢
  • 1970-01-01
  • 2016-12-22
  • 1970-01-01
  • 2019-03-27
  • 1970-01-01
  • 2016-08-10
  • 1970-01-01
  • 2021-02-21
  • 1970-01-01
相关资源
最近更新 更多