【问题标题】:Uncaught DOMException: Failed to execute 'readAsDataURL' on 'FileReader': The object is already busy reading Blobs.(…)未捕获的 DOMException:无法在“FileReader”上执行“readAsDataURL”:对象已经忙于读取 Blob。(…)
【发布时间】:2021-04-24 22:03:13
【问题描述】:

在过去的 6 个小时里,我一直在处理这个问题,但我无法弄清楚这一点。

我正在尝试创建一个网站,在其中我选择一个图像文件夹并将它们显示在我的文档中。我得到了要显示的第一张图像,然后在我的控制台中出现以下错误。

未捕获的 DOMException:无法在“FileReader”上执行“readAsDataURL”:对象已经忙于读取 Blob。(...)

我认为问题是由于我的 for 循环引起的,因为文件读取器是异步的。但是我需要为此遍历整个数组,所以我做错了什么?

我将文件(“稍后将检查以确保我只获得图像”)加载到一个数组中,然后我一次读取每个文件。 在将我的代码分解为函数之前,我在一个函数中完成了所有工作并且它可以工作!我包含了 HTML + 原始和当前的 JS 代码。 感谢您抽出宝贵时间观看此内容。

HTML

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Tiled Image Viewer</title>
    <script src="js/tiv.js"></script>
    <link rel="stylesheet" href="style.css">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

  </head>
  <body>

    <div id="main-wrap">
      <form name="uploadForm">

        <input id="images" type="file" webkitdirectory mozdirectory directory name="myFiles"
                   onchange="readAndShowFiles();" multiple/>

        <span id="list"></span>
      </form>

    </div>

  </body>
</html>

Javascript 原文:

function readAndShowFiles() {
 var files = document.getElementById("images").files;
 for (var i = 0; i < files.length; i++) {
   var file = files[i];
   // Have to check that this is an image though
   // using the file.name TODO
   var reader = new FileReader();
   // Closure to capture the file information.
   reader.onload = (function(file) {
     return function(e) {
       // Render thumbnail.
       var span = document.createElement('span');
       span.innerHTML = ['<img src="', e.target.result,
       '" title="', escape(file.name), '">'].join('');
       document.getElementById('list').insertBefore(span, null);
     };
   })(file);
   // Read in the image file as a data URL.
   reader.readAsDataURL(file);
 }
}

Javascript 当前:

function readAndShowFiles() {
    console.log("Checkpoint2"); //test
    var tiv = new tivAPI();
    var array = tiv.getLoadedImages();
    tiv.showLoadedImages(array);
}

function tivAPI(){
  var imagesarray = new Array();


    return{
      loadImages: function(){
        console.log("Loading Files"); //test
        var files = document.getElementById("images").files;
        for (var i = 0; i < files.length; i++) {
          var file = files[i];
          // Have to check that this is an image though
          // using the file.name TODO
        }
        console.log(files.length); //test
        return files;
      },
      getLoadedImages: function(){
        imagesarray = this.loadImages();
        console.log("Returning Files"); //test
        console.log(imagesarray.length);
        return imagesarray;
      },
      showLoadedImages: function(elem){
        console.log("Showing Files"); //test
        var files = elem;
        var reader = new FileReader();
        // Closure to capture the file information.
        for (var i = 0; i < files.length; i++) {
          var file = files[i];
          reader.onload = (function(file) {
            return function(e) {
              // Render thumbnail.
              var span = document.createElement('span');
               span.innerHTML = ['<img src="', e.target.result,
              '" title="', escape(file.name), '">'].join('');
              document.getElementById('list').insertBefore(span, null);
            };

          })(file);
        // Read in the image file as a data URL.
        reader.readAsDataURL(file);
        }
      }
    };
  }

【问题讨论】:

    标签: javascript


    【解决方案1】:

    您的代码失败的原因是您在每次后续循环迭代中使用相同的 reader 变量。

    当 Javascript 解析你的代码时,所有的变量都会被移动到函数的顶部,所以你的解析代码看起来像这样:

        function readAndShowFiles() {
          var files = document.getElementById("images").files;
          var reader;
          var file;
          var i;
    
          for (i = 0; i < files.length; i++) {
            file = files[i];
            reader = new FileReader();
            reader.onload = (function(file) {
              return function(e) {
                var span = document.createElement('span');
                span.innerHTML = ['<img src="', e.target.result,
                  '" title="', escape(file.name), '">'
                ].join('');
                document.getElementById('list').insertBefore(span, null);
              };
            })(file);
            reader.readAsDataURL(file);
          }
        }
    

    你可以很简单地避免这个错误,只需像这样移动匿名函数中的所有逻辑:

        function readAndShowFiles() {
          var files = document.getElementById("images").files;
    
          for (var i = 0; i < files.length; i++) {
            // Closure to capture the file information.
            (function(file) {
              var reader = new FileReader();
              reader.onload = function(e) {
                // Render thumbnail.
                var span = document.createElement('span');
                span.innerHTML = ['<img src="', e.target.result,
                  '" title="', escape(file.name), '">'
                ].join('');
                document.getElementById('list').insertBefore(span, null);
              };
              // Read in the image file as a data URL.
              reader.readAsDataURL(file);
            })(files[i]);
          }
        }
    

    现在您为每个文件迭代使用一个唯一的读取器变量。另请注意,如果您只是这样做,这可能会更简单:

        array.from(files).forEach(function(file) {
          // code
        })
    

    或者只使用let 变量(这样您每次都会使用不同的FileReader):

        function readAndShowFiles() {
          var files = document.getElementById("images").files;
    
          for (let i = 0; i < files.length; i++) {
            let file = files[i];
            let reader = new FileReader();
            reader.onload = function(e) {
              // Render thumbnail.
              var span = document.createElement('span');
              span.innerHTML = ['<img src="', e.target.result,
                '" title="', escape(file.name), '">'
              ].join('');
              document.getElementById('list').insertBefore(span, null);
            };
            // Read in the image file as a data URL.
            reader.readAsDataURL(file);
          }
        }
    

    使用 es6 可以更轻松地编写 for 循环,从而减少 2 个变量

        function readAndShowFiles() {
          var files = document.getElementById("images").files;
    
          for (let file of files) {
            let reader = new FileReader();
            reader.onload = function(e) {
              // Render thumbnail.
              var span = document.createElement('span');
              span.innerHTML = ['<img src="', e.target.result,
                '" title="', escape(file.name), '">'
              ].join('');
              document.getElementById('list').insertBefore(span, null);
            };
            // Read in the image file as a data URL.
            reader.readAsDataURL(file);
          }
        }
    

    但如果你想要它超级简单,为什么不干脆跳过FileReader 并避免使用URL.createObjectURL 的所有函数和回调?使用createObjectURL 可以节省 CPU 对 base64 的反编译/编译文件:

        function showFiles() {
          var files = document.getElementById("images").files;
    
          for (let file of files) {
            let img = new Image;
            img.src = URL.createObjectURL(file);
            img.title = file.name;
    
            document.getElementById('list').appendChild(img);
          }
        }
    

    【讨论】:

    • 谢谢,我遇到了同样的问题,我刚刚声明了 const reader = new FileReader();在 forEach 外面,但它应该在里面.. 非常感谢
    【解决方案2】:

    出现问题是因为我试图对每张图像使用相同的阅读器。 将 var reader = new FileReader(); 移动到循环中(ShowLoadedImages 函数),解决了这个问题并显示了所有应该显示的图像。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-07
      • 2017-06-24
      • 2022-10-07
      • 2016-02-10
      • 1970-01-01
      • 2021-12-04
      相关资源
      最近更新 更多