我正在try 同步日历,但接收服务器只想要"一口大小"的数据,所以我决定每月同步每个用户.

因此,我做了一个双循环:

首先,我循环遍历所有用户,如果日期范围跨越多个月,则在该循环中循环遍历月份.

但是,因为同步函数是异步的,所以它同时执行多个资源和月份,因为循环不等待完成.

我知道以前也有人问过类似的问题,但出于某种原因,我就是不能让它起作用.

以下是我的功能:

function loopThroughMonths(resourceIds, startDate, endDate) {
  startDateObject = new Date(startDate);
  endDateObject = new Date(endDate);

  // Check how many months our date range spans:

  var dateRangeMonths = monthDiff(startDateObject, endDateObject);

  if (dateRangeMonths > 0) {
    // Loop through each month

    for (let i = 0; i <= dateRangeMonths; i++) {
      if (i == 0) {
        // For the first month, the starting date is equal to the start of the date range

        var loopStartDate = startDate;
        var loopEndDate = formatDate(
          lastDayOfMonth(
            startDateObject.getFullYear(),
            startDateObject.getMonth(),
          ),
        );
      }

      if (i != 0 && i != dateRangeMonths) {
        var loopMonth = new Date(
          startDateObject.getFullYear(),
          startDateObject.getMonth() + i,
          1,
        );
        var loopStartDate = formatDate(
          firstDayOfMonth(loopMonth.getFullYear(), loopMonth.getMonth()),
        );
        var loopEndDate = formatDate(
          lastDayOfMonth(loopMonth.getFullYear(), loopMonth.getMonth()),
        );
      }

      if (i == dateRangeMonths) {
        // For the last month, the end date is equal to the last date of the date range.

        var loopStartDate = formatDate(
          firstDayOfMonth(
            endDateObject.getFullYear(),
            endDateObject.getMonth(),
          ),
        );
        var loopEndDate = endDate;
      }

      loopThroughResources(resourceIds, 0, loopStartDate, loopEndDate);
    }
  } else {
    // Date range falls within 1 month, just proceed to looping through resources

    loopThroughResources(resourceIds, 0, startDate, endDate);
  }
}

function loopThroughResources(resourceIds, i, loopStartDate, loopEndDate) {
  if (i == resourceIds.length) {
    $("#start_exchange")
      .text("Synchroniseren")
      .removeAttr("disabled")
      .css("cursor", "pointer");
    return;
  }
  var resourceId = resourceIds[i];

  $("#exchange_output").append(
    "Start synchroniseren naar Outlook-agenda van " +
      resourceNames.get(resourceId) +
      " van " +
      loopStartDate +
      " tot " +
      loopEndDate +
      "...<br>",
  );

  $.post(
    "sync.php",
    {
      resourceId: resourceId,
      startDate: loopStartDate,
      endDate: loopEndDate,
    },
    function (response) {
      $("#exchange_output").append(response);
      i = i + 1;
      loopThroughResources(resourceIds, i, loopStartDate, loopEndDate);
    },
  );
}

因此,我来解释一下:

LoopThroughMonths首先判断startDate和endDate是否相差0个月以上. 如果是这样的话,它每个月都会看一遍.如果不是,它会立即执行loopThroughResources.

如果日期RangeMonth跨越多个月,我们使用for循环遍历它们,并 for each 月执行loopThroughResources函数.

因此,如果我们说:

从2023-12-27到2024-02-16同步资源A、B、C

它将做到:

Sync 2023-12-27 till 2023-12-31 (part of december 2023) for resource A
Sync 2023-12-27 till 2023-12-31 (part of december 2023) for resource B
Sync 2023-12-27 till 2023-12-31 (part of december 2023) for resource C
Sync 2024-01-01 till 2024-01-31 (whole january 2023) for resource A
Sync 2024-01-01 till 2024-01-31 (whole january 2023) for resource B
Sync 2024-01-01 till 2024-01-31 (whole january 2023) for resource C
Sync 2024-02-01 till 2024-02-16 (part of february 2023) for resource A
Sync 2024-02-01 till 2024-02-16 (part of february 2023) for resource B
Sync 2024-02-01 till 2024-02-16 (part of february 2023) for resource C

代码可以工作,但它不会等待所有资源完成(即在loopThroughResources函数完成之前),然后才继续下个月.

对于资源,我甚至通过从$.post Complete函数调用函数,使其等待资源A的同步完成,然后才继续到资源B,但基本上我需要另一个等待整个loopThroughResources函数(我猜它需要Promiss.all...)

我知道我必须做一些promise ,但我就是不能让它工作. 任何帮助将不胜感激.

推荐答案

如果你把想做的事和做的事分开,你会过得更好:

  • 计算出给定范围内的"日期块"(我的日期计算可能会出错,尤其是在没有外部库的情况下)
  • 计算作业(job),即资源ID+块的组合
  • 发送请求

function toDate(start) {
  return start.toISOString().split("T")[0];
}

function getFirstAndLastDayOfMonth(date) {
  let start = new Date(date);
  let end = new Date(date);
  end.setMonth(end.getMonth() + 1);
  end.setDate(0);
  return {
    start: toDate(start),
    end: toDate(end),
  };
}

function getDateRanges(startDate, endDate) {
  let startDateObject = new Date(startDate);
  let endDateObject = new Date(endDate);
  let ranges = [];
  let date = new Date(startDateObject);
  date.setDate(15);
  while (date < endDateObject) {
    ranges.push(getFirstAndLastDayOfMonth(date));
    date.setMonth(date.getMonth() + 1);
  }
  // Adjust start and end
  ranges[0].start = toDate(startDateObject);
  ranges[ranges.length - 1].end = toDate(endDateObject);
  return ranges;
}

function getSyncJobs(resourceIds, startDate, endDate) {
  const jobs = [];
  const ranges = getDateRanges(startDate, endDate);
  for (let resourceId of resourceIds) {
    for (let range of ranges) {
      jobs.push({
        resourceId,
        startDate: range.start,
        endDate: range.end,
      });
    }
  }
  return jobs;
}

function doJob(params, done) {
  // (do $.post here instead of `setTimeout`...)
  console.log(params);
  setTimeout(done, 500);
}

function go(done) {
  // Build a queue of sync jobs we consume in `doNextJob`
  const syncJobs = getSyncJobs(
    ["A", "B", "C"],
    "2023-12-27",
    "2024-02-16",
  );

  function doNextJob() {
    console.log(`Remaining jobs: ${syncJobs.length}`);
    if (syncJobs.length === 0) {
      return done();
    }
    const job = syncJobs.shift();
    doJob(job, doNextJob);
  }

  doNextJob();
}

go(function () {
  console.log("All done!");
});

如果你能把$.post变成你能做到的await,你就可以完全摆脱回调,执行就变得公正了

async function doJob(job) {
    console.log(job);
    await new Promise(resolve => setTimeout(resolve, 500));
}

async function go() {
  // Build a queue of sync jobs
  const syncJobs = getSyncJobs(
    ["A", "B", "C"],
    "2023-12-27",
    "2024-02-16",
  );

  for(let job of syncJobs) {
      await doJob(job);
  }
  console.log("All done!");
}

Javascript相关问答推荐

获取表格的左滚动位置

Next.js Next/Image图像隐含性有任何类型-如何修复?

如何在表格上拥有水平滚动条,在正文页面上拥有垂直滚动条,同时还对html表格的标题使用位置粘性?

深嵌套的ng-container元素仍然可以在Angular 布局组件中正确渲染内容吗?

在React中获取数据后,如何避免不必要的组件闪现1秒?

模块与独立组件

当试图显示小部件时,使用者会出现JavaScript错误.

为什么!逗号和空格不会作为输出返回,如果它在参数上?

使用ThreeJ渲染的形状具有抖动/模糊的边缘

如何在Angular17 APP中全局设置AXIOS

DOM不自动更新,尽管运行倒计时TS,JS

为什么这个.add.group({})在教程中运行得很好,但在我的游戏中就不行了?

Phaserjs-创建带有层纹理的精灵层以自定义外观

传递方法VS泛型对象VS事件特定对象

通过跳过某些元素的对象进行映射

脚本语法错误只是一个字符串,而不是一个对象?

Played link-Initialize.js永远显示加载符号

Firebase函数中的FireStore WHERE子句无法执行

在每次重新加载页面时更改指针光标

由于http.get,*ngIf的延迟很大