异步中的初始化减少

发布于 2025-02-06 19:34:09 字数 1409 浏览 0 评论 0 原文

  const handleFileChange = async (e) => {
        const target = e?.target?.files;
        const attachments = await Array.from(target).reduce(async (acum, file) => {
            file.id = uniqid();
            // const format = file.name.split('.').pop();
            // if (IMAGE_FORMATS.includes(format)) {
            setIsLoading(true);
            if (file.type.startsWith('image/')) {
                const response = await channel.sendImage(file);
                file.src = response.file;
                acum.images.push(file);
            } else {
                const response = await channel.sendFile(file);
                file.src = response.file;
                acum.files.push(file);
            }
            setIsLoading(false);
            return acum;
        }, Promise.resolve({ files: [], images: [] }));
        setFilesList(prev => {
            console.log('files', [...prev, ...attachments.files]);
            return [...prev, ...attachments.files];
        });
        setImagesList(prev => {
            console.log('images', [...prev, ...attachments.images]);
            return [...prev, ...attachments.images];
        });
    };

在上面的代码中,我有以下错误 它看起来是由于我对数组初始化的原因,但是我应该如何解决它?

  const handleFileChange = async (e) => {
        const target = e?.target?.files;
        const attachments = await Array.from(target).reduce(async (acum, file) => {
            file.id = uniqid();
            // const format = file.name.split('.').pop();
            // if (IMAGE_FORMATS.includes(format)) {
            setIsLoading(true);
            if (file.type.startsWith('image/')) {
                const response = await channel.sendImage(file);
                file.src = response.file;
                acum.images.push(file);
            } else {
                const response = await channel.sendFile(file);
                file.src = response.file;
                acum.files.push(file);
            }
            setIsLoading(false);
            return acum;
        }, Promise.resolve({ files: [], images: [] }));
        setFilesList(prev => {
            console.log('files', [...prev, ...attachments.files]);
            return [...prev, ...attachments.files];
        });
        setImagesList(prev => {
            console.log('images', [...prev, ...attachments.images]);
            return [...prev, ...attachments.images];
        });
    };

In the above code I got the following error
enter image description here
It looks it's cause by my initialization of array, but how should I address it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

空气里的味道 2025-02-13 19:34:09

async 函数返回承诺,这使得使用 .Reduce()时很难使用,因为您需要等待您的累加器每次迭代获取您的数据。作为替代方案,您可以使用 array.from() (您可以将其视为使用 .map())。这里的想法是,该地图将使用 sendimage / sendfile 触发每个文件的多个异步调用。这些呼叫将在后台并行运行。我们从映射函数返回的价值将是一个承诺,它会在成功完成(一旦解决)成功完成时通知我们。此外,映射函数定义了承诺所解决的问题,在我们的情况下,它是带有 src 属性的新对象:

const isImage = file => file.type.startsWith('image/');
const filePromises = Array.from(target, async file => {
  const response = await (isImage(file) ? channel.sendImage(file) : channel. sendFile(file));
  return {...file, type: file.type, src: response.file};
});

上面 filepromises 是一个承诺的数组(如<代码> async mapper函数隐含地返回承诺)。我们可以使用 等待我们解决的所有承诺。这比执行每个异步调用一个逐一呼叫要快,只有在我们等待之前的完成后才移动到下一个:

setIsLoading(true); // set loading to `true` before we start waiting for our asynchronous work to complete
const fileObjects = await Promise.all(filePromises);
setIsLoading(false); // complete asynchronous loading/waiting

最后, fileObjects 是一个数组,它包含所有对象,都包含文件和图像。我们可以进行一次迭代,将此数组分为单独的数组,一个用于图像,一个用于文件:

const attachments = {files: [], images: []};
for(const fileObj of fileObjects) {
  if(isImage(fileObj)) 
    attachments.images.push(fileObj);
  else
    attachments.files.push(fileObj);
}

An async function returns Promise, which makes it difficult to work with when using .reduce() as you would need to await your accumulator each iteration to get your data. As an alternative, you can create an array of Promises using the mapper function of Array.from() (which you can think of as using .map() directly after Array.from()). The idea here is that the map will trigger multiple asynchronous calls for each file by using sendImage/sendFile. These calls will run in parallel in the background. The value that we return from the mapping function will be a Promise that notifies us when the asynchronous call has successfully completed (once it resolves). Moreover, the mapping function defines what the promise resolves with, in our case that is the new object with the src property:

const isImage = file => file.type.startsWith('image/');
const filePromises = Array.from(target, async file => {
  const response = await (isImage(file) ? channel.sendImage(file) : channel. sendFile(file));
  return {...file, type: file.type, src: response.file};
});

Above filePromises is an array of Promises (as the async mapper function returns a Promise implicitly). We can use Promise.all() to wait for all of our Promises to resolve. This is faster than performing each asynchronous call one by one and only moving to the next once we've waited for the previous to complete:

setIsLoading(true); // set loading to `true` before we start waiting for our asynchronous work to complete
const fileObjects = await Promise.all(filePromises);
setIsLoading(false); // complete asynchronous loading/waiting

Lastly, fileObjects is an array that contains all objects, both files and images. We can do one iteration to partition this array into seperate arrays, one for images, and one for files:

const attachments = {files: [], images: []};
for(const fileObj of fileObjects) {
  if(isImage(fileObj)) 
    attachments.images.push(fileObj);
  else
    attachments.files.push(fileObj);
}
信愁 2025-02-13 19:34:09

减少并不是真正的必要

在这一点上,

const channel = {
 sendImage: async (file) => {return {file}},
 sendFile: async (file) => {return {file}}
 }

const uniqid = () => Math.floor(Math.random() * 100);

const input = {
  target: {
    files: [{
      src: 'src',
      type: 'image/123'
      },
      {
      src: 'src',
      type: 'image/321'
      },
      {
      src: 'src',
      type: '123'
      },
      {
      src: 'src',
      type: '321'
      }]
    }
  }
  
const setIsLoading = () => null;
 

const handleFileChange = async (e) => {
  const target = e?.target?.files;

   setIsLoading(true);
    const attachments = {
      images: [],
      files: [],
    }
        
   await Promise.all(Array.from(target).map((file) => {
      file.id = uniqid();
      return new Promise(async (resolve) => {
        if (file.type.startsWith('image/')) {
            const response = await channel.sendImage(file);
            file.src = response.file;
            attachments.images.push(file);
        } else {
            const response = await channel.sendFile(file);
            file.src = response.file;
            attachments.files.push(file);
        }
        resolve();
      });
    }));
    
  setIsLoading(false)

  return attachments;
};

handleFileChange(input).then(res => console.log(res))
    

The reduce is not really necessary at this point:

Here is a solution with a map to transform the elements in promises and then Promise.all to wait for the exectution

const channel = {
 sendImage: async (file) => {return {file}},
 sendFile: async (file) => {return {file}}
 }

const uniqid = () => Math.floor(Math.random() * 100);

const input = {
  target: {
    files: [{
      src: 'src',
      type: 'image/123'
      },
      {
      src: 'src',
      type: 'image/321'
      },
      {
      src: 'src',
      type: '123'
      },
      {
      src: 'src',
      type: '321'
      }]
    }
  }
  
const setIsLoading = () => null;
 

const handleFileChange = async (e) => {
  const target = e?.target?.files;

   setIsLoading(true);
    const attachments = {
      images: [],
      files: [],
    }
        
   await Promise.all(Array.from(target).map((file) => {
      file.id = uniqid();
      return new Promise(async (resolve) => {
        if (file.type.startsWith('image/')) {
            const response = await channel.sendImage(file);
            file.src = response.file;
            attachments.images.push(file);
        } else {
            const response = await channel.sendFile(file);
            file.src = response.file;
            attachments.files.push(file);
        }
        resolve();
      });
    }));
    
  setIsLoading(false)

  return attachments;
};

handleFileChange(input).then(res => console.log(res))
    

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文