我有一个进程以特定的时间间隔运行,比如说它每分钟10秒运行一次。这是一个递归函数,因此在每10秒钟结束时,它会自行调用。到目前为止,这是可行的。
在此计时器函数中,我有一个对API的异步/等待调用。基本上,它的工作是进行API调用,获取数据,并将数据完成%100后将其推送到客户端。
问题是,如果async / await调用花费的时间超过了我的计时器间隔,那么我将开始出现重叠。
因此,这是一个设计问题。我通过在API调用包装函数中使用全局变量找到了解决方案。
var REQUEST_CYCLE_ACTIVE = false;
或
var REQUEST_CYCLE_ACTIVE = true;
在计时器内部,如果API调用未完成,我可以跳过递归,它将在下一个间隔尝试。
这有效。但是我很想知道是否有更优雅的方法来解决这个问题。我还提供了一个示例node.js
应用程序,用于演示问题和解决方案。
// A simple function to simulate resource delays.
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// Construct a time string for debug purposes.
const getTime = () => {
var now = new Date();
var h = now.getHours().toString().padStart(2, '0');
var m = now.getMinutes().toString().padStart(2, '0');
var s = now.getSeconds().toString().padStart(2, '0');
const timeSignature = h + ':' + m + ':' + s;
return timeSignature;
}
// Update
// This is the request wrapper.
const update = async () => {
REQUEST_CYCLE_ACTIVE = true;
let result;
try {
result = await someFakeAPI();
} catch (err) {
throw err;
}
let timeSignature = getTime();
console.log(`\t\t(REQUEST) update() is done. Here is the result:`);
console.log('\t\t', result)
// Once the data is %100 collected here (there are retries etc.)
// we make a call to the websocket and force-push the data to all
// of the connected clients.
// PUSH TO CLIENTS()
REQUEST_CYCLE_ACTIVE = false;
};
// The core mock API call function.
async function someFakeAPI() {
// Emulate an asynchroneous fetch.
console.log('\t\t(REQUEST) Fetching data ...')
// 12000 miliseconds (12 sec) is longer than our timer call.
// There will be an overlap.
await delay(12000);
let result = 0.6; // Change to 0.4 to trigger a failed fetch.
if (result < 0.5) {;
return '__FAIL__';
} else {
return {name: 'apple', price: '1234.12', time: 1549926859970};
}
}
// Just an initial API call to get things started.
async function sendExchangeRequest()
{
let result;
try {
result = await someFakeAPI();
} catch (err) {
throw err;
}
return result;
}
// runClock {{{1
const runClock2 = async () => {
let next_update_seconds;
// This is our interval, the recursive function will be called on every n'th second of the minute.
// For example, an interval of 10 means, the calls will be placed at 22:11:00, 22:11:10, 22:11:20 etc.
var interval = 10; //seconds
var date = new Date();
let current_seconds = date.getSeconds();
let buffer = 60 % interval;
let border = (60 - buffer);
// Interval calculations.
if (current_seconds <= border) {
if ((current_seconds % interval) == 0) {
next_update_seconds = interval;
} else {
let distance = (border - current_seconds);
let slice = (distance % interval);
next_update_seconds = slice;
}
} else {
next_update_seconds = (60 - current_seconds);
}
let next_update_milliseconds = (next_update_seconds * 1000);
var timeToNextTick = (next_update_milliseconds);
let timeSignature = getTime();
console.log(`[4] <${timeSignature}> Starting runClock(), time to next Async REQUEST: ${timeToNextTick}ms`);
setTimeout(function() {
let timeSignature = getTime();
console.log(`\t(${timeSignature}) Time is up, done waiting. Async REQUEST will be called.`);
if(REQUEST_CYCLE_ACTIVE){
console.log(`\t(${timeSignature}) Previous Async REQUEST already running. Skipping ...`);
}else{
console.log(`\t(${timeSignature}) Previous Async REQUEST is complete. Running a new one ...`);
// MAKE THE ASYNC API CALL HERE.
update();
}
// Recursion
console.log(`\t(${timeSignature}) Start runClock() again.`);
runClock2();
}, timeToNextTick);
};
var REQUEST_CYCLE_ACTIVE = false;
(async () => {
console.log('[1] Make the request:')
try {
response = await sendExchangeRequest();
console.log('[2] Report the result:\n\t', response)
console.log('[3] Start the clock cycle.');
runClock2();
} catch(error) {
console.log('FAILED:', error)
}
})();
如果您对所包含的代码有疑问,请参阅以下REPL链接:AsyncConcepts2.repl.run