function first(){
console.log('first')
}
function second(){
console.log('second')
}
let interval = async ()=>{
await setInterval(first,2000)
await setInterval(second,2000)
}
interval();
想象一下,我在上面有这段代码。
当我运行它时,first()
和second()
会同时被调用;first)()
返回一些数据后如何调用second()
,例如,如果first()
完成,则只调用second()
?
因为我的代码first()
将处理大量数据,如果这两个函数同时调用,那么服务器将很难。
每次first()
返回一些数据时如何调用second()
?
如上所述setInterval
如果你不阻止它,它就不能很好地与承诺相提并论。如果您清除间隔,则可以像以下方式使用它:
async function waitUntil(condition) {
return await new Promise(resolve => {
const interval = setInterval(() => {
if (condition) {
resolve('foo');
clearInterval(interval);
};
}, 1000);
});
}
以后你可以像这样使用它
const bar = waitUntil(someConditionHere)
您有几个问题:
- 承诺只能解决一次,
setInterval()
意味着多次调用回调,承诺不能很好地支持这种情况。 - 因此,无论是
setInterval()
,还是更合适的setTimeout()
回报承诺,在这种情况下,await
承诺都是没有意义的。
您正在寻找一个返回 Promise 的函数,该函数会在一段时间后解析(使用setTimeout()
,可能不是setInterval()
(。
幸运的是,创建这样的函数相当简单:
async function delay(ms) {
// return await for better async stack trace support in case of errors.
return await new Promise(resolve => setTimeout(resolve, ms));
}
使用此新的delay
功能,您可以实现所需的流程:
function first(){
console.log('first')
}
function second(){
console.log('second')
}
let run = async ()=>{
await delay(2000);
first();
await delay(2000)
second();
}
run();
setInterval
不能很好地处理承诺,因为它会多次触发回调,而承诺会解析一次。
似乎setTimeout
适合这种情况。它应该被承诺以便与async..await
一起使用:
async () => {
await new Promise(resolve => setTimeout(() => resolve(first()), 2000));
await new Promise(resolve => setTimeout(() => resolve(second()), 2000));
}
await 表达式会导致异步暂停,直到 Promise 被解决
因此,您可以直接获得承诺的结果,而无需等待
对我来说,我想每 1 秒启动一次 Http 请求
let intervalid
async function testFunction() {
intervalid = setInterval(() => {
// I use axios like: axios.get('/user?ID=12345').then
new Promise(function(resolve, reject){
resolve('something')
}).then(res => {
if (condition) {
// do something
} else {
clearInterval(intervalid)
}
})
}, 1000)
}
// you can use this function like
testFunction()
// or stop the setInterval in any place by
clearInterval(intervalid)
你可以使用IFFE。这样,您可以避免myInterval
不接受 Promise 作为返回类型的问题。
在某些情况下,您需要setInterval
,因为您想调用一些未知次数的函数,中间有一些间隔。 当我遇到这个问题时,这对我来说是最直接的解决方案。我希望它能帮助某人:)
对我来说,用例是我想将日志发送到 CloudWatch,但尽量不要遇到每秒发送超过 5 个日志的限制异常。所以我需要保留我的日志,并在 1 秒的间隔内将它们作为批处理发送。我在这里发布的解决方案是我最终使用的解决方案。
async function myAsyncFunc(): Promise<string> {
return new Promise<string>((resolve) => {
resolve("hello world");
});
}
function myInterval(): void {
setInterval(() => {
void (async () => {
await myAsyncFunc();
})();
}, 5_000);
}
// then call like so
myInterval();
查看了所有答案,但仍然没有找到正确的答案,该答案可以完全按照 OP 的要求工作。这是我用于相同目的的:
async function waitInterval(callback, ms) {
return new Promise(resolve => {
let iteration = 0;
const interval = setInterval(async () => {
if (await callback(iteration, interval)) {
resolve();
clearInterval(interval);
}
iteration++;
}, ms);
});
}
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
(async () => {
console.log('start');
await waitInterval(first, 1000);
await waitInterval(second, 1000);
console.log('finish');
})()
在我的示例中,我还放置了间隔迭代计数和计时器本身,以防调用方需要对其进行处理。但是,没有必要
就我而言,我需要遍历图像列表,在每个图像之间暂停,然后在最后暂停更长的时间,然后再重新循环。 我通过结合上面的几种技术来实现这一点,递归调用我的函数并等待超时。 如果在任何时候另一个触发器改变了我的animationPaused:boolean
,我的递归函数将退出。
const loopThroughImages = async() => {
for (let i=0; i<numberOfImages; i++){
if (animationPaused) {
return;
}
this.updateImage(i);
await timeout(700);
}
await timeout(1000);
loopThroughImages();
}
loopThroughImages();
Async/await 不要使承诺同步。 据我所知,这只是return Promise
和.then()
的不同语法。 在这里,我重写了异步函数并保留了两个版本,因此您可以看到它的真正作用并进行比较。 它实际上是一连串的承诺。
// by the way no need for async there. the callback does not return a promise, so no need for await.
function waitInterval(callback, ms) {
return new Promise(resolve => {
let iteration = 0;
const interval = setInterval(async () => {
if (callback(iteration, interval)) {
resolve();
clearInterval(interval);
}
iteration++;
}, ms);
});
}
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
// async function with async/await, this code ...
(async () => {
console.log('start');
await waitInterval(first, 1000);
await waitInterval(second, 1000);
console.log('finish');
})() //... returns a pending Promise and ...
console.log('i do not wait');
// ... is kinda identical to this code.
// still asynchronous but return Promise statements with then cascade.
(() => {
console.log('start again');
return waitInterval(first, 1000).then(() => {
return waitInterval(second, 1000).then(() => {
console.log('finish again');
});
});
})(); // returns a pending Promise...
console.log('i do not wait either');
您可以看到两个异步函数同时执行。 所以在这里使用间隔周围的承诺不是很有用,因为它仍然只是间隔,承诺不会改变任何东西,并且让事情变得混乱......
由于代码在间隔中反复调用回调,我认为这是一种更简洁的方法:
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function executeThroughTime(...callbacks){
console.log('start');
let callbackIndex = 0; // to track current callback.
let timerIndex = 0; // index given to callbacks
let interval = setInterval(() =>{
if (callbacks[callbackIndex](timerIndex++)){ // callback return true when it finishes.
timerIndex = 0; // resets for next callback
if (++callbackIndex>=callbacks.length){ // if no next callback finish.
clearInterval(interval);
console.log('finish');
}
}
},1000)
}
executeThroughTime(first,second);
console.log('and i still do not wait ;)');
此外,此解决方案每秒执行一次回调。 如果回调是需要超过一秒才能解决的异步请求,并且我不能让它们重叠,那么,我将获得请求解析以调用下一个请求(如果我不想骚扰服务器,则通过计时器(。
这里的"递归"任务称为lTask,其功能与以前几乎相同,只是,由于我不再有间隔,因此每次迭代都需要一个新的计时器。
// slow internet request simulation. with a Promise, could be a callback.
function simulateAsync1(i) {
console.log(`first pending: ${i}`);
return new Promise((resolve) =>{
setTimeout(() => resolve('got that first big data'), Math.floor(Math.random()*1000)+ 1000);//simulate request that last between 1 and 2 sec.
}).then((result) =>{
console.log(`first solved: ${i} ->`, result);
return i==2;
});
}
// slow internet request simulation. with a Promise, could be a callback.
function simulateAsync2(i) {
console.log(`second pending: ${i}`);
return new Promise((resolve) =>{
setTimeout(() => resolve('got that second big data'), Math.floor(Math.random()*1000) + 1000);//simulate request that last between 1 and 2 sec.
}).then((result) =>{ // promise is resolved
console.log(`second solved: ${i} ->`,result);
return i==4; // return a promise
});
}
function executeThroughTime(...asyncCallbacks){
console.log('start');
let callbackIndex = 0;
let timerIndex = 0;
let lPreviousTime = Date.now();
let lTask = () => { // timeout callback.
asyncCallbacks[callbackIndex](timerIndex++).then((result) => { // the setTimeout for the next task is set when the promise is solved.
console.log('result',result)
if (result) { // current callback is done.
timerIndex = 0;
if (++callbackIndex>=asyncCallbacks.length){//are all callbacks done ?
console.log('finish');
return;// its over
}
}
console.log('time elapsed since previous call',Date.now() - lPreviousTime);
lPreviousTime = Date.now();
//console.log('"wait" 1 sec (but not realy)');
setTimeout(lTask,1000);//redo task after 1 sec.
//console.log('i do not wait');
});
}
lTask();// no need to set a timer for first call.
}
executeThroughTime(simulateAsync1,simulateAsync2);
console.log('i do not wait');
下一步是用间隔清空 fifo,并用 Web 请求承诺填充它......
import {
setInterval,
} from 'timers/promises';
const interval = 100;
for await (const startTime of setInterval(interval, Date.now())) {
const now = Date.now();
console.log(now);
if ((now - startTime) > 1000)
break;
}
console.log(Date.now());
适用于 nodejs 的解决方案。
https://nodejs.org/api/timers.html#timerspromisessetintervaldelay-value-options