【问题标题】:FileReader readAsText() async issues?FileReader readAsText() 异步问题?
【发布时间】:2019-08-24 19:53:56
【问题描述】:

我已经实现了以下代码来通过 <input type="file" /> 选择解析 CSV:

export async function parse(file: File) {
  let content = '';
  const reader = new FileReader();
  reader.onload = function(e: any) {
    content = e.target.result;
  };
  await reader.readAsText(file);
  const result = content.split(/\r\n|\n/);
  return result;
}

如果我运行此代码并在我声明result 的行上放置一个断点,它将成功检索文件的内容。如果我不放任何断点,则内容为空。如您所见,我在阅读器以文本形式读取文件的行中添加了await,但仍然无法正常工作。

【问题讨论】:

  • 你应该返回一个Promise,而不是返回结果,并在onload监听器中解决它
  • await 在这里没有帮助。 readAsText() 不返回 Promise
  • FileReader is not return a promise try loadend event 这里是MDN

标签: javascript html


【解决方案1】:

await 在这里没有帮助。 readAsText() doesn't return a Promise.

您需要将整个过程包装在Promise

export function parse(file: File) {
  // Always return a Promise
  return new Promise((resolve, reject) => {
    let content = '';
    const reader = new FileReader();
    // Wait till complete
    reader.onloadend = function(e: any) {
      content = e.target.result;
      const result = content.split(/\r\n|\n/);
      resolve(result);
    };
    // Make sure to handle error states
    reader.onerror = function(e: any) {
      reject(e);
    };
    reader.readAsText(file);
  });
}

【讨论】:

  • 知道了。谢谢!
  • 我认为您应该在这里使用onload 而不是onloadend,以避免出现重复的错误回调。 onloadend 的文档说 loadend 事件的处理程序。每次读取操作完成时都会触发此事件(成功或失败)。 developer.mozilla.org/sv-SE/docs/Web/API/FileReader
  • 为什么最后要加reader.readAsText(file);?这不是必须在开头,以便我们有一个文件和其中的文本吗?如果没有readAsText(file)content = e.target.result; 如何工作?
  • @Jorje12 不,是的。在调用reader.readAsText() 之前,我们不会对文件做任何事情。 reader.on* 部分正在设置事件处理程序。你必须在开始阅读之前设置听众,否则你会错过时机。这与处理Image 加载所必须遵循的模式几乎完全相同。在这里查看我的答案:loading an image on web browser using Promise()
  • 这是有道理的。不过,我需要阅读更多关于这些事件的信息。感谢您的快速回答。
【解决方案2】:

这是我尝试过的JSBin,它就像一个魅力。

function parse(file) {
  const reader = new FileReader();
  reader.readAsText(file);
  reader.onload = function(event) {
    // The file's text will be printed here
  console.log(reader.result)
  }
}

更新:

我给你写了一个 Promise 版本。

async function parse(file) {
  const reader = new FileReader();
  reader.readAsText(file);
  const result = await new Promise((resolve, reject) => {
    reader.onload = function(event) {
    resolve(reader.result)
    }
  })
  console.log(result)
}

【讨论】:

  • async 在这里增加了不必要的复杂性。 async 无论如何都会返回一个Promise,所以你不妨返回你已经构建的Promise。否则,您将解开 Promise,然后立即再次包装 Promise
  • @zero298 你说得对,在这种情况下不需要异步,谢谢你的建议。
  • 不应该在调用 reader.readAsText() 之前设置事件处理程序 reader.onload 以避免竞争条件吗?
【解决方案3】:

为了概括@zero298 的答案,这里是FileReader 周围的基于Promise 的通用包装器 -

// get contents of a file as obtained from an html input type=file element
function getFileContents(file) {
  return new Promise((resolve, reject) => {
    let contents = ""
    const reader = new FileReader()
    reader.onloadend = function (e) {
      contents = e.target.result
      resolve(contents)
    }
    reader.onerror = function (e) {
      reject(e)
    }
    reader.readAsText(file)
  })
}

这样使用 -

async function parse(file) {
  const contents = await getFileContents(file)
  const result = contents.split(/\r\n|\n/)
  return result
}

或者在一般情况下,

async function show(file) {
  const contents = await getFileContents(file)
  alert(contents)
}

【讨论】:

  • 我认为您应该在这里使用onload 而不是onloadend,以避免收到重复的错误回调。 onloadend 的文档说 loadend 事件的处理程序。每次读取操作完成时都会触发此事件(成功或失败)。 developer.mozilla.org/sv-SE/docs/Web/API/FileReader
猜你喜欢
  • 2022-10-25
  • 1970-01-01
  • 2018-09-17
  • 1970-01-01
  • 2012-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多