Home > Software engineering >  JavaScript (React): How to extend async function's await to a given time
JavaScript (React): How to extend async function's await to a given time

Time:11-26

I would like to have a async function that sends a request to a server and awaits the response. It will then wait upto 1000ms to ensure that an animation has played out. i was wondering if I could combine these 2 tasks somehow so they add up to having waited 1000ms in total dynamically.

My current code:

const loadingHandler = async (func, target) => {
        setIsLoading(true);

        await new Promise(r => setTimeout(r, 1000));
        await func(target);

        setIsLoading(false);
    };

Some examples to further explain what exactly I mean: the function calls func() and gets a response after (lets say) 200ms. Now the timeout is only supposed to be 800ms. If the func() returns after 20ms the timeout is supposed to be 980ms. If func() takes longer than 1000ms it should continue immedietly after getting the response and not wait additionally. So is something like this 'stretcher await function' possible?

CodePudding user response:

Sure, just remember how long it's been so far, then delay that much longer:

const loadingHandler = async (func, target) => {
    setIsLoading(true);

    const started = Date.now();
    await func(target);
    const elapsed = Date.now() - started;
    const delayFurther = 1000 - elapsed;
    if (delayFurther > 0) {
        await new Promise(r => setTimeout(r, delayFurther));
    }

    setIsLoading(false);
};

That said, holding up the user because an animation hasn't finished might not be the best UX. Perhaps you could make the animation finish more quickly when func is already done. (Humans tend to notice delays > about 80-100ms, a bit less when we're younger.)

CodePudding user response:

An alternative to Mr Crowder's perfectly valid solution: Rather than wait for the promise to finish and then checking if we need to start a new one, start two promises at the same time and wait for them both. Has the same effect, but makes the code shorter:

const loadingHandler = async (func, target) => {
  setIsLoading(true);
  await Promise.all([
    func(target),
    new Promise(r => setTimeout(r, 1000)),
  ]);
  setIsLoading(false);
}

CodePudding user response:

In your code you starts first promise (interval), waits for it to finish, then starts second (func) and wait to finish. You should start both promises and wait for it together.

const loadingHandler = async (func, target) => {
        setIsLoading(true);

        const p1 = new Promise(r => setTimeout(r, 1000));
        const p2 = func(target);
    
        await Promise.all([p1,p2]);

        setIsLoading(false);
    };
  • Related