Home > Back-end >  Async operation in queue javascript
Async operation in queue javascript

Time:09-27

I am working with react functional component.

I have download(async) functionality in my application. There is list of download buttons in my app. I want to download them one by one in queue.

const [downloadQueue, setDownloadQueue] = useState([]);

onClickDonwload = () => { //on every download click this function calls. So user can click on download continuously but I want to make sure them to be downloaded one by one.
  downloadQueue([...downloadQueue, { id, data }])
}

useEffect(() => {
  downloadQueue.map(async(data) => {
    await myDownloadAsyncFunction()
  })
}, [downloadQueue])  // here the issue is whenever the downloadQueue updates it just start downloading without waiting for the previous one

Kindly help

CodePudding user response:

How about this? It uses Promise-chaining to make a simple queue

import React, { useState } from "react";

// Any async function or function that returns a promise
async function myDownloadAsyncFunction(data) {
  return fetch('https://mydomain.test/path');
}

function DownloadButton() {
  const [queue, setQueue] = useState(Promise.resolve());

  onClickDownload = () => {
    setQueue(queue
      .then(() => myDownloadAsyncFunction('My data'))
      .catch((err) => {console.error(err)})
    )
  }

  return (
    <button onClick={onClickDownload}>Download</button>
  );
}

The above doesn't trigger the download from useEffect. If you do want to use useEffect, I think the state would probably need to be a counter to cause useEffect to run when it changes:

import React, { useState, useEffect, useRef } from "react";

// Any async function or function that returns a promise
async function myDownloadAsyncFunction(data) {
  return fetch('https://mydomain.test/path');
}

function DownloadButton() {
  const queue = useRef(Promise.resolve());
  const [clickCount, setClickCount] = useState(0);

  useEffect(() => {
    if (clickCount == 0) return;
    queue.current = queue.current
      .then(() => myDownloadAsyncFunction('My data'))
      .catch((err) => {console.error(err)});
  }, [clickCount]);

  function onClickDownload() {
    setClickCount(clickCount   1);
  }

  return (
    <button onClick={onClickDownload}>Download</button>
  );
}

Note in both of the above examples might need to get more complicated to better deal with some of the downloads failing. In these examples though, if a download fails, the next one should continue to attempt to be downloaded.

CodePudding user response:

A simple way is :

const [downloading,setDownloading] = useState(false)

useEffect( ()=> {
  if(downloadQueue.length && !downloading){
    myDownloadAsyncFunction(downloadQueue[0].data).then(()=>{
      setDownloading(false)
      setDownLoadQueue((a) => a.slice(1))
    })
  }
},[downloadQueue])

From your code, I'm not sure how do you pass parameter to myDownloadAsyncFunction(). Here I juse assume that it use downloadQueue[0].data.

  • Related