Google Apps 脚本日历服务:分块处理许多事件:如何以编程方式触发下一个函数 运行 继续下一个块?

Google Apps Script Calendar Service: Process many events in chunks: How to programmatically trigger next function run to continue with next chunk?

我指的是

function renameEvents() {
  var cal = CalendarApp.getCalendarById("Calendar Id");
  var startTime = new Date(1850, 0, 1);
  var endTime = new Date(2100, 0, 1);
  var events = cal.getEvents(startTime, endTime);
  var sp = PropertiesService.getScriptProperties();
  if (!(sp.getProperty("count")) || sp.getProperty("count") == 0) {
    var count = 0;
  else if ((sp.getProperty("count") > 0) {
    var count = sp.getProperty("count");
  }

  for (var i = count; i < events.length; i++) {
    events[i].setTitle(events[i].getTitle() + " something");
    events[i].setDescription(events[i].getDescription() + " something else");
    sp.setProperty("count", i)
  }
}

初始函数运行是时间触发的。如何以编程方式触发下一个函数 运行 继续下一个块?

我相信你的目标如下。

  • 您想降低以下脚本的处理成本。该脚本来自您问题中的 the URL

    var cal = CalendarApp.getCalendarById("Calendar Id");
    var startTime = new Date(1850, 0, 1);
    var endTime = new Date(2100, 0, 1);
    var events = cal.getEvents(startTime, endTime);
    for (var i = 0; i < events.length; i++) {
      events[i].setTitle(events[i].getTitle() + " something");
      events[i].setDescription(events[i].getDescription() + " something else");
    }
    
  • 您想修改Google日历中所有活动的活动标题和活动描述。

问题和解决方法:

  • 在您当前的脚本中,所有事件的标题和事件描述都尝试在for循环中修改。在您当前的脚本中,循环是 运行 直到发生错误。当错误发生时,使用 time-driven 触发器从 count 开始循环。我是这样理解的。
  • 在你上面的脚本中,当事件数量很大时,最大执行时间已经结束。因为我觉得setTitlesetDescription成本高
  • 在您当前的脚本中,除了setTitlesetDescription之外,for循环中还使用了setProperty。这样的话,工艺成本会更高。

在我的回答中,作为一种解决方法,我建议针对您的情况使用 the batch request。日历 API 可以被批量请求 运行。批量请求是运行异步处理,一次API调用可以运行100个请求。由此,可以降低工艺成本。所以我想当批量请求用于你的情况时,你的所有任务可能可以通过一个 运行ning 脚本来实现。

用法:

1。安装 Google Apps 脚本库。

为了使用此示例脚本,请安装 BatchRequest. You can see the method for installing the library at https://github.com/tanaikech/BatchRequest#how-to-install 的 Google Apps 脚本库。

2。 运行 示例脚本。

请复制并粘贴以下脚本。并且 please enable Google Calendar API at Advanced Google services。并且请将您的日历 ID 设置为 calendarId.

function myFunction() {
  const calendarId = "###";

  var cal = CalendarApp.getCalendarById(calendarId);
  var startTime = new Date(1850, 0, 1);
  var endTime = new Date(2100, 0, 1);
  var events = cal.getEvents(startTime, endTime);

  // Create requests for the batch request.
  const reqs = events.map(e => ({
    method: "PUT",
    endpoint: `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events/${e.getId().replace("@google.com", "")}`,
    requestBody: {
      start: {dateTime: e.getStartTime().toISOString()},
      end: {dateTime: e.getEndTime().toISOString()},
      summary: e.getTitle() + " something",
      description: e.getDescription() + " something else"
    }
  }));

  // Run batch requests.
  const limit = 100;
  const split = Math.ceil(reqs.length / limit);
  for (let i = 0; i < split; i++) {
    BatchRequest.Do({batchPath: "batch/calendar/v3", requests: reqs.splice(0, limit)});
  }
}
  • 当你运行myFunction的功能时,所有事件的标题和描述都通过Events:update in CalendarAPI的方法修改。

注:

  • 此脚本修改所有事件的标题和描述。所以请注意这一点。所以一开始,作为测试运行,我想测试小事件数
  • 在我的环境中,当我针对 100 个事件测试上述脚本时,处理时间约为 7 秒。我不确定你的总事件数。
  • 在这个回答中,我建议使用Events:update的方法,而不是Events:patch的方法。因为在使用Events: patch的时候,我确认只修改了requested all events的一部分。我认为这可能是一个错误。所以我用了"Events: update"的方法。在这种情况下,我可以确认所有事件都已修改。
  • 请在 V8 中使用此脚本。

参考文献:

已添加:

在此示例脚本中,没有使用 GAS 库。

示例脚本:

function myFunction() {
  const calendarId = "###";

  var cal = CalendarApp.getCalendarById(calendarId);
  var startTime = new Date(1850, 0, 1);
  var endTime = new Date(2100, 0, 1);
  var events = cal.getEvents(startTime, endTime);

  // Create requests for the batch request.
  const reqs = events.map(e => ({
    method: "PUT",
    endpoint: `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events/${e.getId().replace("@google.com", "")}`,
    requestBody: {
      start: {dateTime: e.getStartTime().toISOString()},
      end: {dateTime: e.getEndTime().toISOString()},
      summary: e.getTitle() + " something",
      description: e.getDescription() + " something else"
    }
  }));

  // Run batch requests.
  const limit = 100;
  const split = Math.ceil(reqs.length / limit);
  const boundary = "xxxxxxxxxx";
  for (let i = 0; i < split; i++) {
    const object = {batchPath: "batch/calendar/v3", requests: reqs.splice(0, limit)};
    const payload = object.requests.reduce((s, e, i) => s += "Content-Type: application/http\r\nContent-ID: " + i + "\r\n\r\n" + e.method + " " + e.endpoint + "\r\nContent-Type: application/json; charset=utf-8\r\n\r\n" + JSON.stringify(e.requestBody) + "\r\n--" + boundary + "\r\n", "--" + boundary + "\r\n");
    const params = {method: "post", contentType: "multipart/mixed; boundary=" + boundary, payload: payload, headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}, muteHttpExceptions: true};
    UrlFetchApp.fetch("https://www.googleapis.com/" + object.batchPath, params);
  }
}

已添加:

  • 您想在不使用日历的情况下实现上述目标 API。

为此,这个修改怎么样?

修改点:

  • 在您的脚本中,以下部分存在语法错误。

    if (!(sp.getProperty("count")) || sp.getProperty("count") == 0) {
      var count = 0;
    else if ((sp.getProperty("count") > 0) {
      var count = sp.getProperty("count");
    }
    
    • 请将else if ((sp.getProperty("count") > 0) {修改为} else if (sp.getProperty("count") > 0) {
  • getProperty获取的值是字符串类型。从 your replying 中的 nothing happes,我认为这可能是您问题的原因。

那么下面的修改呢?

修改后的脚本:

从:
if (!(sp.getProperty("count")) || sp.getProperty("count") == 0) {
  var count = 0;
else if ((sp.getProperty("count") > 0) {
  var count = sp.getProperty("count");
}
到:
var count = Number(sp.getProperty("count")) || 0;

参考: