我对 debounce axios 请求的实现使承诺永远处于挂起状态,有没有更好的方法? [英] My implementation of debounce axios request left the promise in pending state forever, is there a better way?

查看:18
本文介绍了我对 debounce axios 请求的实现使承诺永远处于挂起状态,有没有更好的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个简单的 debounce 函数,立即数总是为真.
无需求助于 lodash 并在 有人可以解释去抖动"的帮助下;Javascript 中的函数,我实现如下,

I need a simple debounce function with immediate always true.
Without resorting to lodash and with the help of Can someone explain the "debounce" function in Javascript , I implemented it as following,

function debounce(func, wait) {
    var timeout;
    return function() {
        if (!timeout) func.apply(this, arguments);
        clearTimeout(timeout);
        timeout = setTimeout(()=>{timeout = null}, wait);
    };
};

它按预期工作,直到我需要去抖动 axios 请求.假设我有一个去抖动的 axios 方法,我希望调用方法和往常一样,这意味着我的去抖动 axios 方法应该返回我相信的承诺.

It works as expected until I need to debounce axios request. Assumed I have a debounced axios method, I would like the calling method to be as usual, which means my debounced axios method should return promise I believe.

   //the calling method should not change   
   debounced_axios().then(res => {...}).catch(err => {...}) 

原始 debounce 实现的本质是在等待时间范围内只运行 func 一次,但是我如何在等待时间范围内只返回 one 承诺?

The essence of original debounce implementation is to just run func once in a wait timeframe, but how do I just return one promise in a wait timeframe ?

然后我想出了以下解决方案

Then I came up with the following solution

all_timers = {}
function debounce_axios(input, wait) {
    return new Promise((resolve, reject) => {
        let timer = all_timers.[input] //check if it is a repeated request, pseudo code
        if (!timer) {
            axios(input).then(res=>{
                resolve(res)
            }).catch(err => {
                reject(err)
            })
        }
        clearTimeout(timer);
        timer = setTimeout(()=>{timer = null}, wait);
        all_timers[input] = timer
    };
};

所以我的debounce_axios的本质就是让promise在重复请求时保持pending状态.然后调用方法debounced_axios().then(res => {...}).catch(err=> {...}) 不需要更改.

So the essence of my debounce_axios is to let the promise stay in pending state for the repeated request.Then the calling method debounced_axios().then(res => {...}).catch(err => {...}) does not need to change.

这里的答案JavaScript 永久未决的承诺是否糟糕? 说应该没有副作用."

The answer here Are JavaScript forever-pending promises bad? said "There should be no side effect."

但我仍然不能 100% 确定让承诺永远悬而未决.

But I am still not 100% sure about letting a promise stay in pending forever.

另一个问题是Promise Anti patterns 建议不要创建不必要的承诺.但就我而言,创建一个新的承诺似乎是必要的.

The other question is that Promise Anti patterns suggested not creating unnecessary promise. But in my case creating a new promise seems necessary.

简而言之,是否有一种简单的方法来消除 axios 请求(或任何请求返回承诺)?

In a nutshell is there a simple to way to debounce axios request (or any request returns promise) ?

推荐答案

但我仍然不能 100% 确定让承诺永远悬而未决.

But I am still not 100% sure about letting a promise stay in pending forever.

我同意这不是一个好主意.更好的方法是将整个 promise 链移动到 debounced 函数中.

I agree that it's not a good idea. A better approach would be to move the entire promise chain inside the debounced function.

另一种选择是在去抖动调用未触发新请求时返回缓存值.这将解决您始终需要返回承诺的问题:

Another option would be to return a cached value when the debounced call does not trigger a new request. This would solve your problem that you always need to return a promise:

function debounce(func, wait) {
    var timeout, value;
    return function() {
        if (!timeout) value = func.apply(this, arguments);
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            timeout = value = null;
        }, wait);
        return value;
    };
}

当然,这意味着在某些情况下,当您的请求完成时,将调用多个 then 处理程序.这取决于您的应用程序是问题还是多余的工作.

Of course that would mean that in some cases, multiple then handlers will be called when your request finishes. It depends on your application whether that is a problem or just superfluous work.

另一个问题是 Promise Anti 模式建议不要创建不必要的承诺.但在我的情况下,创建一个新的承诺似乎是必要的.

The other question is that Promise Anti patterns suggested not creating unnecessary promise. But in my case creating a new promise seems necessary.

只有一个承诺是必要的:当你创建一个从未解决的承诺时.你可以把它写成

Only one promise is necessary: when you create the never-resolved one. You can write that as

function debounce(func, wait) {
    var timeout;
    const never = new Promise(resolve => {/* do nothing*/});
    return function() {
        const result = timeout ? never : func.apply(this, arguments);
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            timeout = null;
        }, wait);
        return result;
    };
}

或者至少避免 .then(resolve).catch(reject) 部分.写得更好

Or at least avoid the .then(resolve).catch(reject) part. Better write

function debounce(func, wait) {
    var timeout;
    return function() {
        return new Promise(resolve => {
            if (!timeout) resolve(func.apply(this, arguments));
//                        ^^^^^^^
            clearTimeout(timeout);
            timeout = setTimeout(() => {
                timeout = null;
            }, wait);
        });
    };
}

如果您考虑在超时尚未发生的情况下拒绝承诺(以便调用代码可以处理拒绝),您也不需要 new Promise :

And should you consider to reject the promise in case that the timeout has not yet occurred (so that the calling code can handle the rejection), you don't need new Promise either:

function debounce(func, wait) {
    var timeout;
    return function() {
        const result = timeout
          ? Promise.reject(new Error("called during debounce period"))
          : Promise.resolve(func.apply(this, arguments));
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            timeout = null;
        }, wait);
        return result;
    };
}

这篇关于我对 debounce axios 请求的实现使承诺永远处于挂起状态,有没有更好的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆