【问题标题】:How to use callback inside loop?如何在循环内使用回调?
【发布时间】:2020-01-14 11:01:15
【问题描述】:

背景是我允许用户将多个文件拖入 Dropzone。我需要检查每种文件类型。如果其中一个不允许,请设置消息并尽早退出。

请看下面的代码 开始于for (let i = 0; i < acceptedFiles.length; i++) { 在这个 for 循环中,我调用 reader.onloadend,这是一个回调。

如何在 for 循环中运行回调?

// Keep it internal
  const getMimetype = signature => {
    switch (signature) {
      case '89504E47':
        return 'image/png';
      case '47494638':
        return 'image/gif';
      case '25504446':
        return 'application/pdf';
      case 'FFD8FFDB':
      case 'FFD8FFE0':
        return 'image/jpeg';
      case '504B0304':
        return 'application/zip';
      default:
        return 'Unknown filetype';
    }
  };

  const onDropAccepted = useCallback(acceptedFiles => {
    // reset to default state
    resetToDefaultState();

    //test
    console.log('acceptedFiles', acceptedFiles);

    // reader
    const reader = new FileReader();
    let file;

    // Multi
    if (config.isMultipleFiles === true) {
      // Loop all files and check file types
      for (let i = 0; i < acceptedFiles.length; i++) {
        file = acceptedFiles[i];
        // get 1st 4 byptes
        const blob = file.slice(0, 4);
        reader.readAsArrayBuffer(blob);

        reader.onloadend = evt => {
          if (evt.target.readyState === FileReader.DONE) {
            const uint = new Uint8Array(evt.target.result);
            let bytes = [];
            uint.forEach(byte => {
              bytes.push(byte.toString(16));
            });

            const hex = bytes.join('').toUpperCase();
            const type = getMimetype(hex);

            // type is allowed
            if (config.fileTypes.includes(type)) {
              setFiles([...files, ...acceptedFiles]);
            } else {
              // type no good
              setIsInvaildFileType(true);
            }
          }
        };
      }
    } else {
      // drop 1 file
      if (acceptedFiles.length <= 1) {
        // bucket no file
        if (files.length === 0) {
          file = acceptedFiles[0];
          // 1st 4 bytes
          const blob = file.slice(0, 4);
          // read 4 bytes
          reader.readAsArrayBuffer(blob);

          // later
          reader.onloadend = evt => {
            if (evt.target.readyState === FileReader.DONE) {
              // event res to unit
              const uint = new Uint8Array(evt.target.result);
              // byte
              let bytes = [];
              // loop each unit
              uint.forEach(byte => {
                bytes.push(byte.toString(16));
              });
              // hex
              const hex = bytes.join('').toUpperCase();
              const type = getMimetype(hex);

              //test
              console.log('hex', hex);
              console.log('output', type);

              // type is allowed
              if (config.fileTypes.includes(type)) {
                setFiles([...files, ...acceptedFiles]);
              } else {
                // type no good
                setIsInvaildFileType(true);
              }
            }
          };
        } else {
          // bucket has file already
          setIsMaxFileNum(true);
        }
      } else {
        // drop multiple files, no thinking of bucket
        setIsMaxFileNum(true);
      }
    }
  });

【问题讨论】:

  • 您不运行回调,而是浏览器调用您的reader.onloadend 方法。还有什么不适用于此代码?不清楚你的问题

标签: javascript reactjs loops callback


【解决方案1】:

我还必须以类似的方式使用 react-dropzone 验证每个文件。
我的解决方法是承诺FileReader

1️⃣ This is the promisified version of "FileReader"
const isValidFile = file => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = evt => {
      // other logic removed for brevity...

      2️⃣ Your custom logic dictates, if the file is valid or not
      if (config.fileTypes.includes(type)) {
        resolve(true);
      } else {
        resolve(false);
      }
    };

    3️⃣ Should there was an error, this file is not good.
    reader.onerror = () => resolve(false)

    4️⃣ Start the reading process.
    const blob = file.slice(0, 4);
    reader.readAsArrayBuffer(blob);
  });
};

现在您可以在您提到的 for 循环中使用它。

const onDropAccepted = useCallback(acceptedFiles => {
  // reset to default state
  resetToDefaultState();

  1️⃣ As `useCallback` accepts a non-async method,
      Create a wrapped async method we can call here.
  const processFiles = async () => {
    if (config.isMultipleFiles === true) {
      for (let i = 0; i < acceptedFiles.length; i++) {
        const file = acceptedFiles[i];
        2️⃣ Here is where we validate the file using the code above.
        const isValid = await isValidFile(file);
        if (!isValid) {
          setIsInvaildFileType(true);
          return;
        }
      }

      3️⃣ At this point, all files are good.
      setFiles([...files, ...acceptedFiles]);
    } else {
      // removed for brevity...
    }
  };

  4️⃣ Let's fire up the process
  processFiles();
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 1970-01-01
    • 2012-02-14
    • 1970-01-01
    • 2018-08-22
    相关资源
    最近更新 更多