尝试使用 setTimeout() 每 5 秒 space XMLHttpRequest() API 调用时出现问题
Issues when trying to space XMLHttpRequest() API calls every 5 seconds with setTimeout()
我正在为一个项目处理初始数据拉取。它将被缓存并且进一步的请求将会少得多。我正在尝试每 5 秒 space 发出我的 API 请求,以避免服务器过载并达到他们规则的速率限制。我的 setTimeout()
函数似乎并没有按预期正常工作。我记录了时间戳以查看所有迭代似乎都在同一时间发生。我认为这是由于 javascript 的异步性质造成的,但我不确定如何补救。任何帮助将不胜感激。
代码摘录:
var leagues;
function getLeagues(){
var reqURL = "url";
var data = new XMLHttpRequest();
data.open("GET", reqURL);
data.responseType = "text";
data.send();
// parse data on load
data.onload = function() {
// League IDs
leagues = JSON.parse(data.response)
for (i = 0; i < 5; i++) {
delay(i); // iterate every 5 secs
}
};
}
function delay(i) {
setTimeout(() => {
var d = new Date();
console.log(d.getSeconds())
}, 5000);
}
你调用delay
告诉JS在5秒内做某事
然后你立即调用delay
告诉JS在5秒内再次做某事。
所以 5 秒后第一个 delay
超时触发,紧接着第二个超时触发。
如果您想 space 将它们分开,则您需要:
- 在 setTimeout 调用的函数中第二次调用延迟,因此第二个计时器不会在第一个计时器完成后启动
- 将你的时间相乘,第一个是 5 秒,第二个是 10 秒,依此类推
- 重构代码以改用
setInterval
您可以使用 Promise 而不是超时。 setTimeout
函数将等待五秒钟,所有代码都将被执行,因为它不会阻止执行。相反,承诺会做到这一点:
async function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
};
您可以在异步循环中使用 promise:
async function getLeagues(){
var reqURL = "url";
var data = new XMLHttpRequest();
data.open("GET", reqURL);
data.responseType = "text";
data.send();
// parse data on load
data.onload = function() {
// League IDs
leagues = JSON.parse(data.response)
const delays = [...new Array(5)]; // To have something to loop over
for await (const d of delays) {
await delay(5000);
}
};
}
function delay(i) {
setTimeout(() => {
var d = new Date();
console.log(d.getSeconds())
}, i * 5000);
}
设置超时的过程,即调用 setTimeout() — 几乎不需要任何时间。如果发出连续的超时请求,每个请求的延迟值都是相同的,那么一旦该时间量过去了……所有的定时器处理程序将被快速连续调用。如果您需要每隔一段时间调用处理程序,您可以使用 setInterval(),它的调用方式与 setTimeout() 完全相同,但会在重复延迟 5000 次后多次触发,或者您可以建立超时并乘以您的迭代计数器的时间值,即 'i' 在这种情况下。 i的值乘以原来的延迟值,所以循环调用5次会延迟5秒、10秒、15秒、20秒、25秒。
setTimeout
是一个浏览器 API,它不会保证准确的执行延迟时间,而是保证执行功能的最短时间,因此它与 js
无关。
setTimeout
导致浏览器在 x 毫秒后设置一个定时器,当完成时你传递的函数将在事件队列中,但它不一定会执行,如果事件队列完全为空,你很幸运,函数在 5 秒后立即执行,否则函数必须在队列中等待,直到每个函数都在之前执行,所以我们有(5 秒 + 一些时间,直到函数进入队列头部然后被执行)。
按顺序调用 setTimeout
五次(使用 for
循环)并具有相同的延迟时间,将在事件队列中添加相同的函数 5 次,所有这些都将同时执行时间,因为所有这些都使用了相同的时间延迟。所以解决方案是为每个功能使用不同的延迟时间。
我会针对同样的问题提出解决方案,因为我遇到过很多
基于回调的解决方案
repeat(processingRequest, 5, 5000);
function processingRequest(){
console.log('Making request at', new Date().getTime());
}
function repeat(func, howManyTimes, milliSecondsInterval){
if(howManyTimes > 0)
delay(() => {
func();
howManyTimes--;
repeat(func, howManyTimes, milliSecondsInterval);
}, milliSecondsInterval);
}
function delay(func, milliSeconds){
setTimeout(func, milliSeconds);
}
基于承诺的解决方案(更优选)
repeat(processingRequest, 5, 5000);
function processingRequest(){
console.log('Making request at', new Date().getTime());
}
function repeat(func, howManyTimes, milliSeconds){
delay(milliSeconds)
.then(() => {
func();
howManyTimes--;
if(howManyTimes > 0)
repeat(func, howManyTimes, milliSeconds);
});
}
function delay(milliSeconds){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, milliSeconds);
});
}
使用像 rxjs 这样的库(提供 repeat
和 delay
)将使事情变得更加简单
https://rxjs-dev.firebaseapp.com/api/operators/repeat
https://rxjs-dev.firebaseapp.com/api/operators/delay
尽管不是每个应用程序都需要 rxjs,但我们不得不说它为程序员提供了强大的干净同步或异步操作能力
[参考文献]
有关浏览器 API 和事件队列
的进一步知识
Philip Roberts 的精彩演讲
https://youtu.be/8aGhZQkoFbQ?t=1165
来自我找到的最好的 js
资源
https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/async%20%26%20performance/ch1.md
我正在为一个项目处理初始数据拉取。它将被缓存并且进一步的请求将会少得多。我正在尝试每 5 秒 space 发出我的 API 请求,以避免服务器过载并达到他们规则的速率限制。我的 setTimeout()
函数似乎并没有按预期正常工作。我记录了时间戳以查看所有迭代似乎都在同一时间发生。我认为这是由于 javascript 的异步性质造成的,但我不确定如何补救。任何帮助将不胜感激。
代码摘录:
var leagues;
function getLeagues(){
var reqURL = "url";
var data = new XMLHttpRequest();
data.open("GET", reqURL);
data.responseType = "text";
data.send();
// parse data on load
data.onload = function() {
// League IDs
leagues = JSON.parse(data.response)
for (i = 0; i < 5; i++) {
delay(i); // iterate every 5 secs
}
};
}
function delay(i) {
setTimeout(() => {
var d = new Date();
console.log(d.getSeconds())
}, 5000);
}
你调用delay
告诉JS在5秒内做某事
然后你立即调用delay
告诉JS在5秒内再次做某事。
所以 5 秒后第一个 delay
超时触发,紧接着第二个超时触发。
如果您想 space 将它们分开,则您需要:
- 在 setTimeout 调用的函数中第二次调用延迟,因此第二个计时器不会在第一个计时器完成后启动
- 将你的时间相乘,第一个是 5 秒,第二个是 10 秒,依此类推
- 重构代码以改用
setInterval
您可以使用 Promise 而不是超时。 setTimeout
函数将等待五秒钟,所有代码都将被执行,因为它不会阻止执行。相反,承诺会做到这一点:
async function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
};
您可以在异步循环中使用 promise:
async function getLeagues(){
var reqURL = "url";
var data = new XMLHttpRequest();
data.open("GET", reqURL);
data.responseType = "text";
data.send();
// parse data on load
data.onload = function() {
// League IDs
leagues = JSON.parse(data.response)
const delays = [...new Array(5)]; // To have something to loop over
for await (const d of delays) {
await delay(5000);
}
};
}
function delay(i) {
setTimeout(() => {
var d = new Date();
console.log(d.getSeconds())
}, i * 5000);
}
设置超时的过程,即调用 setTimeout() — 几乎不需要任何时间。如果发出连续的超时请求,每个请求的延迟值都是相同的,那么一旦该时间量过去了……所有的定时器处理程序将被快速连续调用。如果您需要每隔一段时间调用处理程序,您可以使用 setInterval(),它的调用方式与 setTimeout() 完全相同,但会在重复延迟 5000 次后多次触发,或者您可以建立超时并乘以您的迭代计数器的时间值,即 'i' 在这种情况下。 i的值乘以原来的延迟值,所以循环调用5次会延迟5秒、10秒、15秒、20秒、25秒。
setTimeout
是一个浏览器 API,它不会保证准确的执行延迟时间,而是保证执行功能的最短时间,因此它与 js
无关。
setTimeout
导致浏览器在 x 毫秒后设置一个定时器,当完成时你传递的函数将在事件队列中,但它不一定会执行,如果事件队列完全为空,你很幸运,函数在 5 秒后立即执行,否则函数必须在队列中等待,直到每个函数都在之前执行,所以我们有(5 秒 + 一些时间,直到函数进入队列头部然后被执行)。
按顺序调用 setTimeout
五次(使用 for
循环)并具有相同的延迟时间,将在事件队列中添加相同的函数 5 次,所有这些都将同时执行时间,因为所有这些都使用了相同的时间延迟。所以解决方案是为每个功能使用不同的延迟时间。
我会针对同样的问题提出解决方案,因为我遇到过很多
基于回调的解决方案
repeat(processingRequest, 5, 5000);
function processingRequest(){
console.log('Making request at', new Date().getTime());
}
function repeat(func, howManyTimes, milliSecondsInterval){
if(howManyTimes > 0)
delay(() => {
func();
howManyTimes--;
repeat(func, howManyTimes, milliSecondsInterval);
}, milliSecondsInterval);
}
function delay(func, milliSeconds){
setTimeout(func, milliSeconds);
}
基于承诺的解决方案(更优选)
repeat(processingRequest, 5, 5000);
function processingRequest(){
console.log('Making request at', new Date().getTime());
}
function repeat(func, howManyTimes, milliSeconds){
delay(milliSeconds)
.then(() => {
func();
howManyTimes--;
if(howManyTimes > 0)
repeat(func, howManyTimes, milliSeconds);
});
}
function delay(milliSeconds){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, milliSeconds);
});
}
使用像 rxjs 这样的库(提供 repeat
和 delay
)将使事情变得更加简单
https://rxjs-dev.firebaseapp.com/api/operators/repeat
https://rxjs-dev.firebaseapp.com/api/operators/delay
尽管不是每个应用程序都需要 rxjs,但我们不得不说它为程序员提供了强大的干净同步或异步操作能力
[参考文献]
有关浏览器 API 和事件队列
的进一步知识Philip Roberts 的精彩演讲
https://youtu.be/8aGhZQkoFbQ?t=1165
来自我找到的最好的 js
资源
https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/async%20%26%20performance/ch1.md