首页 > 解决方案 > 文件选择器导致 Chrome 冻结

问题描述

我构建了一个组件,允许用户通过单击文件或直接将文件拖放到文件上来上传文件。大多数情况下这工作得很好,但我注意到它会导致谷歌浏览器(版本 94.0.4606.81)经常完全冻结,而不是打开文件选择器。它仍然可以让我按 Ctrl+W 关闭选项卡,但其他选项卡也将保持对鼠标单击无响应。我被迫关闭整个浏览器。但是,我无法在 Microsoft Edge 中重现这一点。

    const fileInput = document.querySelector("#fileInput");
    const dropArea = document.querySelector("#dropArea");
    const upload = document.querySelector("#upload");
    
    function onDragBegin(e) {
      e.preventDefault();
      e.dataTransfer.dropEffect = "copy";
      dropArea.classList.add("dropArea-highlight");
      upload.classList.add("upload-highlight");
    }
    
    function onDragEnd(e) {
      e.preventDefault();
      dropArea.classList.remove("dropArea-highlight");
      upload.classList.remove("upload-highlight");
    }
    
    function onDrop(e) {
      fileInput.files = e.dataTransfer.files;
      fileInput.dispatchEvent(new Event("change"));
      e.preventDefault();
    }
    
    async function onChangeFileInput() {
      const { files } = this;
    
      dropArea.classList.remove("dropArea-highlight");
      upload.classList.remove("upload-highlight");
    
      const url = "/api/har";
      const formData = new FormData();
      formData.append("harFile", files[0]);
    
      fetch(url, {
        method: "POST",
        body: formData,
      }).then(async (res) => {
        if (!res.ok) {
          const text = await res.text();
          alert(text);
        }
    
        if (res.redirected) {
          window.location.href = res.url;
        }
      });
    }
    
    dropArea.ondragover = onDragBegin;
    dropArea.ondragenter = onDragBegin;
    dropArea.ondragleave = onDragEnd;
    dropArea.ondrop = onDrop;
    
    fileInput.addEventListener("change", onChangeFileInput);
.upload {
      border: 1px dashed var(--copytext-grey);
      background-color: #e7eaef;
    }
    
    .upload:hover {
      background-color: #e1e4ea;
      border-style: dotted;
    }
    
    .upload-icon {
      height: 64px;
      filter: invert(36%) sepia(13%) saturate(381%) hue-rotate(171deg)
        brightness(93%) contrast(91%);
      margin-bottom: 16px;
    }
    
    #dropArea {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      padding: 4rem 1rem;
    }
    
    #dropArea:hover {
      cursor: pointer;
    }
    
    #dropArea h3 {
      color: #555d66;
      font-weight: bold;
    }
    
    #dropArea p {
      color: #676f77;
    }
    
    #fileInput {
      display: none;
    }
    
    .upload-highlight {
      background-color: #e1e4ea;
      border-style: dotted;
    }
    
    .dropArea-highlight {
      cursor: pointer;
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <link rel="stylesheet" href="style.css">
      <script src="upload.js" defer></script>
    </head>
    <body>
    
      <div class="upload" id="upload">
        <label for="fileInput">
          <div id="dropArea">
            <img src="upload.svg" class="upload-icon">
            <h3>Drag and drop or click</h3>
            <p>to upload your file</p>
            <input type="file" name="harFile" id="fileInput" accept=".har">
          </div>
        </label>
      </div>
    
    </body>
    </html>

我已经做了一个错误报告,但同时我需要找到一个修复程序来阻止浏览器冻结。如何?

标签: javascripthtmlgoogle-chrome

解决方案


鉴于这不是您的代码有问题,因此很难解决该问题。(我的猜测是操作系统无法从中获取元数据的某些注册错误的文件,或者某些网络驱动器(Dropbox、icloud)连接不正确)。

我能想到的唯一解决方法是新的文件系统访问API,希望它不会触发 Chrome 的问题(我认为它们不应该需要相同的元数据)。但是我绝对不确定这是否会发生,所以请告诉我,因为我自己无法重现该问题。
此外,此 API 目前仅在基于 Chromium 的浏览器中受支持,因此您仍然需要<input type=file>其他浏览器的后备。

由于此 API 在沙盒 iframe 中不可用,因此现场演示存在故障。

// we need to be handling a click event
document.querySelector("button").onclick = async () => {
  if( !("showOpenFilePicker" in self) ) {
    console.error("unsupported browser, should fallback to <input type=file>");
    return;
  }

  const handles = await showOpenFilePicker();
  const file = await handles[0].getFile();
  // now you can handle the file as usual
  document.getElementById( "log" ).textContent = await file.text();
};

推荐阅读