如何实现多用户多日历月同步的异步循环串行执行?
解决方案
要实现「按月串行同步,每个月内资源串行同步」的需求,核心是把异步操作包装成Promise,再用async/await控制执行顺序:
1. 改造loopThroughResources为Promise版本
将原来的回调式$.post包装成Promise,让整个函数返回Promise,外部可以等待它执行完成:
function loopThroughResources(resourceIds, i, loopStartDate, loopEndDate) { // 递归终止条件,返回已完成的Promise if (i == resourceIds.length) { $("#start_exchange") .text("Synchroniseren") .removeAttr("disabled") .css("cursor", "pointer"); return Promise.resolve(); } const resourceId = resourceIds[i]; $("#exchange_output").append( "Start synchroniseren naar Outlook-agenda van " + resourceNames.get(resourceId) + " van " + loopStartDate + " tot " + loopEndDate + "...<br>", ); // 封装$.post为Promise return new Promise((resolve, reject) => { $.post( "sync.php", { resourceId: resourceId, startDate: loopStartDate, endDate: loopEndDate, }, function (response) { $("#exchange_output").append(response); // 递归调用下一个资源,等待完成后resolve当前Promise loopThroughResources(resourceIds, i + 1, loopStartDate, loopEndDate) .then(resolve) .catch(reject); } ).fail(reject); // 处理请求失败场景 }); }
2. 改造loopThroughMonths为异步函数
将loopThroughMonths改为async函数,遍历月份时逐个await当前月份的资源同步完成,再进入下一个月份:
async function loopThroughMonths(resourceIds, startDate, endDate) { const startDateObject = new Date(startDate); const endDateObject = new Date(endDate); // 计算日期范围跨越的月份数 const dateRangeMonths = monthDiff(startDateObject, endDateObject); if (dateRangeMonths > 0) { // 遍历每个月份,用for循环+await实现串行执行 for (let i = 0; i <= dateRangeMonths; i++) { let loopStartDate, loopEndDate; if (i == 0) { // 第一个月:起始为原范围开始,结束为当月最后一天 loopStartDate = startDate; loopEndDate = formatDate( lastDayOfMonth( startDateObject.getFullYear(), startDateObject.getMonth(), ), ); } else if (i != dateRangeMonths) { // 中间月份:整月范围 const loopMonth = new Date( startDateObject.getFullYear(), startDateObject.getMonth() + i, 1, ); loopStartDate = formatDate( firstDayOfMonth(loopMonth.getFullYear(), loopMonth.getMonth()), ); loopEndDate = formatDate( lastDayOfMonth(loopMonth.getFullYear(), loopMonth.getMonth()), ); } else { // 最后一个月:起始为当月第一天,结束为原范围结束 loopStartDate = formatDate( firstDayOfMonth( endDateObject.getFullYear(), endDateObject.getMonth(), ), ); loopEndDate = endDate; } // 等待当前月份所有资源同步完成,再进入下一个循环 await loopThroughResources(resourceIds, 0, loopStartDate, loopEndDate); } } else { // 日期范围在一个月内,直接等待资源同步完成 await loopThroughResources(resourceIds, 0, startDate, endDate); } }
3. 调用方式
调用时可通过.catch()处理同步异常:
loopThroughMonths(yourResourceIds, yourStartDate, yourEndDate) .catch(err => { console.error('同步出错:', err); // 可添加前端错误提示逻辑 });
核心逻辑说明
- 把
$.post包装成Promise,让异步操作具备可等待性 loopThroughResources递归时,每个步骤都返回Promise,形成完整的异步链路,确保整个月份的资源同步完成后才会resolveloopThroughMonths用async/await配合for循环,强制月份之间串行执行,避免多月份同步同时触发
内容的提问来源于stack exchange,提问作者Laurens Swart
相关产品推荐
相关产品推荐

