我对 debounce axios 请求的实现使承诺永远处于挂起状态,有没有更好的方法?

Qiu*_*ang 7 javascript promise debouncing es6-promise axios

我需要一个简单的 debounce 函数,立即数总是为真。
没有求助于 lodash 并在有人可以解释 Javascript 中的“去抖动”功能的帮助下,我实现了它如下,

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

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

   //the calling method should not change   
   debounced_axios().then(res => {...}).catch(err => {...}) 
Run Code Online (Sandbox Code Playgroud)

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

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

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
    };
};
Run Code Online (Sandbox Code Playgroud)

所以我的debounce_axios的本质就是让promise对于重复的请求保持pending状态,那么调用方法debounced_axios().then(res => {...}).catch(err => {...})就不用改了。

这里的答案是 JavaScript 永远未决的承诺是坏的吗?说:“应该没有副作用。”

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

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

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

Ber*_*rgi 4

但我仍然不能 100% 确定是否让 Promise 永远处于待处理状态。

我同意这不是一个好主意。更好的方法是将整个 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;
    };
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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;
    };
}
Run Code Online (Sandbox Code Playgroud)

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

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);
        });
    };
}
Run Code Online (Sandbox Code Playgroud)

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

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;
    };
}
Run Code Online (Sandbox Code Playgroud)