我的 debounce axios 请求的实现让 promise 永远处于挂起状态,有没有更好的方法?
My implementation of debounce axios request left the promise in pending state forever, is there a better way?
我需要一个简单的去抖动函数,立即数总是为真。
在不求助于 lodash 的情况下,在 Can someone explain the "debounce" function in Javascript 的帮助下,我按如下方式实现了它,
function debounce(func, wait) {
var timeout;
return function() {
if (!timeout) func.apply(this, arguments);
clearTimeout(timeout);
timeout = setTimeout(()=>{timeout = null}, wait);
};
};
它按预期工作,直到我需要对 axios 请求进行反跳。假设我有一个去抖动的 axios 方法,我希望调用方法像往常一样,这意味着我相信我的去抖动 axios 方法应该 return 承诺。
//the calling method should not change
debounced_axios().then(res => {...}).catch(err => {...})
原始去抖实现的本质是在等待时间范围内运行 func 一次,但我如何return 一个 承诺在等待时间范围内?
然后我想出了以下解决方案
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在重复request.Then的时候一直处于pending状态,调用方法debounced_axios().then(res => {...}).catch(err => {...})
不需要改变
这里的回答表示"There should be no side effect."
但我仍然不能 100% 确定是否让承诺永远悬而未决。
另一个问题是 Promise Anti patterns 建议不要创建不必要的承诺。但就我而言,创建一个新的承诺似乎是必要的。
简而言之,是否有一种简单的方法来消除 axios 请求(或任何请求 return 的承诺)?
本质上,您需要分享去抖功能的结果。在你的情况下,这是一个承诺:
const debouncedGetData = debounce(getData, 500)
let promiseCount = 0
let resultCount = 0
test()
function test() {
console.log('start')
callDebouncedThreeTimes()
setTimeout(callDebouncedThreeTimes, 200)
setTimeout(callDebouncedThreeTimes, 900)
}
function callDebouncedThreeTimes () {
for (let i=0; i<3; i++) {
debouncedGetData().then(r => {
console.log('Result count:', ++resultCount)
console.log('r', r)
})
}
}
function debounce(func, wait) {
let waiting;
let sharedResult;
return function() {
// first call will create the promise|value here
if (!waiting) {
setTimeout(clearWait, wait)
waiting = true
sharedResult = func.apply(this, arguments);
}
// else new calls within waitTime will be discarded but shared the result from first call
function clearWait() {
waiting = null
sharedResult = null
}
return sharedResult
};
}
function getData () {
console.log('Promise count:', ++promiseCount)
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(666)
}, 1000)
})
}
But I am still not 100% sure about letting a promise stay in pending forever.
我同意这不是个好主意。更好的方法是将整个承诺链移动到 debounced 函数中。
另一种选择是 return 去抖调用未触发新请求时的缓存值。这将解决您始终需要 return 承诺的问题:
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
处理程序。这取决于您的应用程序,这是一个问题还是多余的工作。
The other question is that Promise Anti patterns suggested not creating unnecessary promise. But in my case creating a new promise seems necessary.
只需要一个承诺:当您创建一个从未解决的承诺时。你可以写成
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)
部分。最好写
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
:
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;
};
}
我需要一个简单的去抖动函数,立即数总是为真。
在不求助于 lodash 的情况下,在 Can someone explain the "debounce" function in Javascript 的帮助下,我按如下方式实现了它,
function debounce(func, wait) {
var timeout;
return function() {
if (!timeout) func.apply(this, arguments);
clearTimeout(timeout);
timeout = setTimeout(()=>{timeout = null}, wait);
};
};
它按预期工作,直到我需要对 axios 请求进行反跳。假设我有一个去抖动的 axios 方法,我希望调用方法像往常一样,这意味着我相信我的去抖动 axios 方法应该 return 承诺。
//the calling method should not change
debounced_axios().then(res => {...}).catch(err => {...})
原始去抖实现的本质是在等待时间范围内运行 func 一次,但我如何return 一个 承诺在等待时间范围内?
然后我想出了以下解决方案
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在重复request.Then的时候一直处于pending状态,调用方法debounced_axios().then(res => {...}).catch(err => {...})
不需要改变
这里的回答
但我仍然不能 100% 确定是否让承诺永远悬而未决。
另一个问题是 Promise Anti patterns 建议不要创建不必要的承诺。但就我而言,创建一个新的承诺似乎是必要的。
简而言之,是否有一种简单的方法来消除 axios 请求(或任何请求 return 的承诺)?
本质上,您需要分享去抖功能的结果。在你的情况下,这是一个承诺:
const debouncedGetData = debounce(getData, 500)
let promiseCount = 0
let resultCount = 0
test()
function test() {
console.log('start')
callDebouncedThreeTimes()
setTimeout(callDebouncedThreeTimes, 200)
setTimeout(callDebouncedThreeTimes, 900)
}
function callDebouncedThreeTimes () {
for (let i=0; i<3; i++) {
debouncedGetData().then(r => {
console.log('Result count:', ++resultCount)
console.log('r', r)
})
}
}
function debounce(func, wait) {
let waiting;
let sharedResult;
return function() {
// first call will create the promise|value here
if (!waiting) {
setTimeout(clearWait, wait)
waiting = true
sharedResult = func.apply(this, arguments);
}
// else new calls within waitTime will be discarded but shared the result from first call
function clearWait() {
waiting = null
sharedResult = null
}
return sharedResult
};
}
function getData () {
console.log('Promise count:', ++promiseCount)
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(666)
}, 1000)
})
}
But I am still not 100% sure about letting a promise stay in pending forever.
我同意这不是个好主意。更好的方法是将整个承诺链移动到 debounced 函数中。
另一种选择是 return 去抖调用未触发新请求时的缓存值。这将解决您始终需要 return 承诺的问题:
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
处理程序。这取决于您的应用程序,这是一个问题还是多余的工作。
The other question is that Promise Anti patterns suggested not creating unnecessary promise. But in my case creating a new promise seems necessary.
只需要一个承诺:当您创建一个从未解决的承诺时。你可以写成
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)
部分。最好写
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
:
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;
};
}