我正在尝试创建一个延迟异步函数执行X ms的函数。
出于本演示的目的,以下是异步函数,它采用URL:
/*
* This is a simulation of an async function. Be imaginative!
*/
let asyncMock = function(url) {
return new Promise(fulfil => {
setTimeout(() => {
fulfil({
url,
data: "banana"
});
}, 10000);
});
};
我的目标是拥有一个函数,该函数将采用url
的{{1}}参数,然后每隔X ms调用一次,或直到不再有参数为止。
基本上,我希望asyncMock
的每次调用都以X ms分隔。
举个例子,假设我连续20次调用asyncMock
。通常,这20个电话会立即完成。我想要的是,它确保在20个呼叫中的每个呼叫之间存在Xms的延迟。
我解决这个问题的想法是建立一个工厂,它将返回一个promise,它将在X ms后执行该函数。
asyncMock
理想情况下,我会像下面的示例中那样使用这个工厂:
let throttleFactory = function(args) {
let {
throttleMs
} = args;
let promise = Promise.resolve();
let throttleAsync = function(url) {
return promise.then(() => {
setTimeout(anUrl => {
return new Promise( fulfil => {
fulfil(asyncMock(anUrl));
});
}, throttleMs, url);
});
};
return Object.freeze({
throttleAsync
});
};
这里的问题是我的let throttleFuns = throttleFactory({
throttleMs: 2000
});
console.log('running');
throttleFuns.throttleAsync('http://www.bananas.pt')
.then(console.log)
.catch(console.error);
throttleFuns.throttleAsync('http://www.fruits.es')
.then(console.log)
.catch(console.error);
throttleFuns.throttleAsync('http://www.veggies.com')
.then(console.log)
.catch(console.error);
// a ton of other calls in random places in code
功能立即输出throttleAsync
三次。我相信这可能是因为我没有正确定义undefined
。
如何修复此代码以按预期工作?
答案 0 :(得分:5)
因为throttleAsync
会返回调用promise.then
的结果,并且then
回调不会返回任何内容。这使得then
创建的承诺以值undefined
解析。
您可能希望让它返回您正在创建的新承诺,但在setTimeout
回调之前您不会这样做。你想先做(但还有更多,继续阅读):
let throttleAsync = function(url) {
return promise.then(() => {
return new Promise( fulfil => {
setTimeout(anUrl => {
fulfil(asyncMock(anUrl));
}, throttleMs, url);
});
});
};
也没有理由像这样通过setTimeout
传递网址,所以:
let throttleAsync = function(url) {
return promise.then(() => {
return new Promise( fulfil => {
setTimeout(() => {
fulfil(asyncMock(url));
}, throttleMs);
});
});
};
最初我虽然promise
没有必要,但你已经澄清了你想要确保重复的电话被throttleMs
“隔开”。为此,我们将使用上述内容,但请更新promise
:
let throttleAsync = function(url) {
return promise = promise.then(() => {
// ^^^^^^^^^
return new Promise( fulfil => {
setTimeout(() => {
fulfil(asyncMock(url));
}, throttleMs);
});
});
};
这样,对asyncThrottle
的下一次调用将等到上一次调用之后才开始下一次调用。
直播示例:
const throttleMs = 1000;
const asyncMock = url => url;
let promise = Promise.resolve();
let throttleAsync = function(url) {
return promise = promise.then(() => {
// ^^^^^^^^^
return new Promise( fulfil => {
setTimeout(() => {
fulfil(asyncMock(url));
}, throttleMs);
});
});
};
console.log('running');
throttleAsync('http://www.bananas.pt')
.then(console.log)
.catch(console.error);
throttleAsync('http://www.fruits.es')
.then(console.log)
.catch(console.error);
throttleAsync('http://www.veggies.com')
.then(console.log)
.catch(console.error);
答案 1 :(得分:1)
这是你的问题:
setTimeout(anUrl => {
return new Promise( fulfil => {
fulfil(asyncMock(anUrl));
});
}, throttleMs, url);
你在这里做的是从setTimeout回调中返回一个promise。由setTimeout运行的函数的返回值将被忽略,因此没有人会获得该值。