背景
我正在尝试创建一个工厂函数,该函数可以在给定延迟后执行特定的异步函数。
为了解决这个问题,以下是我所指的异步函数:
/*
* 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
,并返回一个包含该URL和一些数据的JSON对象。在我的代码中,我以以下方式调用这个函数:
asyncMock('http://www.bananas.pt')
.then(console.log);
asyncMock('http://www.berries.com')
.then(console.log);
//... badjillion more calls
asyncMock('http://www.oranges.es')
.then(console.log);
问题
这里的问题是所有这些调用都在完全相同的时间内进行,从而过载了asyncMoc
正在使用的资源。
目标
为了避免上述问题,我希望延迟对asyncMoc
的所有调用X毫秒。
以下是我想要的图形:
为了实现这一点,我编写了以下方法:
- 使用Promises
- 使用setInterval
使用Promises
let asyncMock = function(url) {
return new Promise(fulfil => {
setTimeout(() => {
fulfil({
url,
data: "banana"
});
}, 10000);
});
};
let delayFactory = function(args) {
let {
delayMs
} = args;
let promise = Promise.resolve();
let delayAsync = function(url) {
return promise = promise.then(() => {
return new Promise(fulfil => {
setTimeout(() => {
console.log(`made request to ${url}`);
fulfil(asyncMock(url));
}, delayMs);
});
});
};
return Object.freeze({
delayAsync
});
};
/*
* All calls to any of its functions will have a separation of X ms, and will
* all be executed in the order they were called.
*/
let delayer = delayFactory({
delayMs: 500
});
console.log('running');
delayer.delayAsync('http://www.bananas.pt')
.then(console.log)
.catch(console.error);
delayer.delayAsync('http://www.fruits.es')
.then(console.log)
.catch(console.error);
delayer.delayAsync('http://www.veggies.com')
.then(console.log)
.catch(console.error);
delayAsync
的函数,可以使所有对asyncMock
的调用延迟500毫秒。 然而,它也强制执行调用的嵌套等待前一个调用的结果,这是不打算的。目标是在500毫秒内分别进行三次对
asyncMock
的调用,并在10秒后获得具有500毫秒差异的三个响应。
使用setInterval
在这种方法中,我的目标是拥有一个包含参数数组的工厂。然后,每隔500毫秒,计时器将运行一个执行程序,该执行程序将从该数组中取出一个参数并返回一个带有该参数的结果:/*
* This is a simulation of an async function. Be imaginative!
*/
let asyncMock = function(url) {
return new Promise(fulfil => {
setTimeout(() => {
fulfil({
url,
data: "banana"
});
}, 10000);
});
};
let delayFactory = function(args) {
let {
throttleMs
} = args;
let argsList = [];
let timer;
/*
* Every time this function is called, I add the url argument to a list of
* arguments. Then when the time comes, I take out the oldest argument and
* I run the mockGet function with it, effectively making a queue.
*/
let delayAsync = function(url) {
argsList.push(url);
return new Promise(fulfil => {
if (timer === undefined) {
console.log('created timer');
timer = setInterval(() => {
if (argsList.length === 0) {
clearInterval(timer);
timer = undefined;
} else {
let arg = argsList.shift();
console.log('making request ' + url);
fulfil(asyncMock(arg));
}
}, throttleMs);
} else {
//what if the timer is already running? I need to somehow
//connect it to this call!
}
});
};
return Object.freeze({
delayAsync
});
};
/*
* All calls to any of its functions will have a separation of X ms, and will
* all be executed in the order they were called.
*/
let delayer = delayFactory({
delayMs: 500
});
console.log('running');
delayer.delayAsync('http://www.bananas.pt')
.then(console.log)
.catch(console.error);
delayer.delayAsync('http://www.fruits.es')
.then(console.log)
.catch(console.error);
delayer.delayAsync('http://www.veggies.com')
.then(console.log)
.catch(console.error);
// a ton of other calls in random places in code
这段代码更糟糕。它无任何延迟地执行了三次 asyncMoch
,总是使用相同的参数,然后由于我不知道如何完成我的 else
分支,所以什么也没做。
问题:
- 哪种方法更好来达到我的目标,如何修复它?
url
对于所有调用来说始终是上一次函数调用中使用的吗?如果是这样,那么我在你的代码中没有遇到这个问题。 - Arg0nthrottleAsync
的Promise(我猜现在是delayAsync
)是否需要基于asyncMock
的Promise的解决方案来解决? - T.J. CrowderthrottleAsync
可以根据它接收到的请求来解决,那就太棒了。但我并没有看到实现这一点的方法。 - Flame_Phoenix