最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to take only last response from asyncawait function - Stack Overflow

programmeradmin1浏览0评论

How to ignore all old called async/await functions if multiple async/await functions is called.

For example, this is my example.

let isLoading = false;

const onResponse = dateTime => {
  console.log(dateTime);
  isLoading = false;
}

const asyncFunction = async () => {
  await delay(1000);
  return new Date();
}

Now for example, if I called the function asyncFunction 3 times within 1 seconds, then I will take onResponse 3 times and my variable isLoading work improperly.

function loadData() {
  isLoading = true;
  asyncFunction.then(onResponse);
}

How can I take response only from last call and ignore all earlier others.

How to ignore all old called async/await functions if multiple async/await functions is called.

For example, this is my example.

let isLoading = false;

const onResponse = dateTime => {
  console.log(dateTime);
  isLoading = false;
}

const asyncFunction = async () => {
  await delay(1000);
  return new Date();
}

Now for example, if I called the function asyncFunction 3 times within 1 seconds, then I will take onResponse 3 times and my variable isLoading work improperly.

function loadData() {
  isLoading = true;
  asyncFunction.then(onResponse);
}

How can I take response only from last call and ignore all earlier others.

Share Improve this question edited Mar 3, 2020 at 7:57 Nick Viatick asked Mar 3, 2020 at 7:35 Nick ViatickNick Viatick 2651 gold badge4 silver badges19 bronze badges 11
  • There is no native method to cancel a promise is js – Maheer Ali Commented Mar 3, 2020 at 7:45
  • @MaheerAli so is there any way to handle this case? – Nick Viatick Commented Mar 3, 2020 at 7:47
  • Just overwrite the variable, and it will always contain the last value. If you want to wait till all three promises are resolved, await Promise.all. – Amadan Commented Mar 3, 2020 at 7:48
  • 1 The point of debouncing it to ignore the stacking events, not cancelling the ones prior. – Robo Robok Commented Mar 3, 2020 at 7:54
  • 1 OP wants to ignore the old calls, just like aborting fetch or Ajax. – Robo Robok Commented Mar 3, 2020 at 7:59
 |  Show 6 more ments

6 Answers 6

Reset to default 2

I would just store some value and increment it every time you call your async function. Then, in the handler you can check if that value is still the same. If not, just return - it means that there was another call afterwards.

My answer was removed because I had sent directly link of debouncing. I have just wanted to explain what was in my head.

Here is the my solution that is like the below example. You can improve or change the code block depending on your needing. Simply it's canceled the previous calling. In my opinion, It's not the perfect solution. But one of the solutions to the problem.

const onResponse = dateTime => {
  console.log(dateTime);
}

const asyncFunction = async () => {
  await setTimeout(() => {}, 1000);
  return new Date();
}

function debounce (callback, delay) {
    let timeout;

    return function (then) {
        const that = this;
        clearTimeout(timeout);
        timeout = setTimeout(() => callback.apply(that, []).then(then), delay);
    };
}

const debouncedFunction = debounce(asyncFunction, 100);

debouncedFunction(onResponse);
debouncedFunction(onResponse);
debouncedFunction(onResponse);
debouncedFunction(onResponse);

here's an implemetation of Robo Robok's answer (if you upvote me, upvote him too)

let isLoading = false;
let promiseCounter = 0;

const delay = time => new Promise(res => setTimeout(() => {res()}, time))

// use a destructuring assignement
const onResponse = ({dateTime, promiseId}) => {
  // refuse promise if it was not the last
  if (promiseId !== promiseCounter) {return;}
  // reset counter to avoir overflow on really long run
  promiseCounter = 0;
  
  // do what needs to be done
  console.log("onResponse", dateTime);
  isLoading = false;
}

const asyncFunction = async () => {
  const promiseId = ++promiseCounter;
  await delay(1000);
  return {dateTime: new Date(), promiseId};
}

function loadData() {
  isLoading = true;
  asyncFunction().then(onResponse);
}

(async ()=>{
  // simulate multiple calls with a total interval > delay of one resposne
  console.log("first call at", new Date())
  loadData()
  for (let i = 0; i < 100; i++) {
    await delay(30);
    loadData()
  }
  console.log("last call at", new Date())
})()

doc : destructuring assignement

If you only want the last pleted result something like this should work:

let finalResult;

const workFunc = async () => {
   finalResult = new Date();
}

await Promise.all([ workFunc(), workFunc(), workFunc() ]);

console.log(finalResult);

The following code defines a function latest that can be applied to a function to ensure only the latest call is run to pletion.

A variable curr records the latest invocation by storing the latest promise. A function is configured in the then position to mediate continuation. Progress along the promise chain is only permitted if the promise in progress is equal to curr. ie. a subsequent invocation has not overwritten curr in the interim.

So the following code prints out: stale two.

function latest(fn) {
    let curr = null
    return (...args) => {
        let p = fn(...args).then((result) =>  { 
            if(p === curr) return result
            else throw 'stale' 
        })
        curr = p
        return p
    }
}

const doSomething = (v, ms) => new Promise((r)=> setTimeout(() => r(v), ms))
const latestDoSomething = latest(doSomething)

latestDoSomething('one', 100).then(console.log).catch(console.log)
latestDoSomething('two', 100).then(console.log).catch(console.log)

You can use Promise.All:

await Promise.all([Call1(), Call2(), Call3(),...]).then(values => { 
  //values is [value1,value2,....,lastValue]
  console.log(values[values.length-1]); last value is in the last entry
});
发布评论

评论列表(0)

  1. 暂无评论