是否可以在 Apps 脚本中获取新鲜的 Google 幻灯片演示数据?

Is it possible to get fresh Google Slides presentation data in AppsScript?

看来如果在AppsScript中使用SlidesApp.getActivePresentation(),函数的结果不是新鲜的,而是事先准备好的东西。

场景

假设您有两个用户同时在 AppsScript 中执行以下功能:

function updateSlideText(slideId) {
  // Request exclusive write access to the document
  var lock = LockService.getDocumentLock();
  lock.waitLock(15000);

  // Perform changes
  var presentation = SlidesApp.getActivePresentation();
  var textBox = presentation.getSlideById(MY_SLIDE_ID).getPageElementById(MY_TEXTBOX_ID);
  textBox.asShape().getText().setText('My text');

  // Save and release lock
  presentation.saveAndClose();
  lock.releaseLock();
}

如果同时调用此函数两次,生成的幻灯片包含文本 "My textMy text"。

当我在锁定释放之前添加 Utilities.sleep(10000) 时,它会将第二次执行延迟 10 秒,但在这 10 秒之后我仍然得到相同的结果。另一方面,如果我真的延迟 调用 函数 10 秒,输出就没问题。

由此我得出结论,如果我调用 saveAndClose 并使用锁并不重要。一旦函数被调用,它总是会有陈旧的数据。有没有解决的办法?获取锁后不能请求加载新数据吗?

更多详情

更多伪代码以更好地说明问题用例:

// The addon frontend
websocket.onMessage((message) => {
  if (message.type === 'pollUpdate') {
    const slideWithPoll = store.getState().slides.find(
      slide => slide.pollId === message.pollId
    );

    if (slideWithPoll.title !== message.poll.title) {
      google.script.run.updateSlideText(slideWithPoll.id, message.poll.title);
    }
  }
});

我相信你的目标如下。

  • 当 2 个用户是 运行 您的 Google 幻灯片的脚本时,同时,您想要单独 运行 脚本。

为此,这个答案怎么样?

问题和解决方法:

当我测试你的情况时,我可以确认与 My textMy text 相同的问题。当我多次测试时,在这种情况下,我认为 LockService 可能不会影响 Google Slides。因此,作为一种解决方法,我想建议使用 Web 应用程序作为包装器。因为已经知道 Web 应用程序可以 运行 由 LockService 独占。此解决方法的流程如下。

  1. 当脚本为运行时,脚本请求Web Apps。
  2. 在 Web Apps,您的脚本是 运行。

这样,即使脚本是运行,同时,脚本也可以与LockService独占运行。

用法:

本示例脚本的用法如下。请按照以下流程进行。

1。准备脚本。

当你的脚本被使用时,变成如下。请将以下脚本复制并粘贴到脚本编辑器中。请设置 MY_SLIDE_IDMY_TEXTBOX_ID.

function doGet() {

  // This is your script.
  var presentation = SlidesApp.getActivePresentation();
  var textBox = presentation.getSlideById(MY_SLIDE_ID).getPageElementById(MY_TEXTBOX_ID);
  var text = textBox.asShape().getText();
  text.setText('My text');

  return ContentService.createTextOutput("ok");
}

// Please run this function.
function main() {
  var lock = LockService.getDocumentLock();
  if (lock.tryLock(10000)) {
    try {
      const url = "https://script.google.com/macros/s/###/exec";  // Please set the URL of Web Apps after you set the Web Apps.
      const res = UrlFetchApp.fetch(url);
      console.log(res.getContentText())
    } catch(e) {
      throw new Error(e);
    } finally {
      lock.releaseLock();
    }
  }
}

2。部署 Web 应用程序。

  1. 在脚本编辑器上,通过"Publish" -> "Deploy as web app"打开一个对话框。
  2. Select "Me" 对于 "Execute the app as:"
    • 至此,脚本运行作为所有者。
  3. Select "Anyone, even anonymous" 对于 "Who has access to the app:"
    • 在这种情况下,请求不需要访问令牌。我认为我建议使用此设置来测试此解决方法。
    • 当然,你也可以使用access token。届时请设置为"Anyone"。并且请将 https://www.googleapis.com/auth/drive.readonlyhttps://www.googleapis.com/auth/drive 的范围包含在访问令牌中。这些范围是访问 Web 应用程序所必需的。
  4. 单击 "Deploy" 按钮作为新按钮 "Project version"。
  5. 自动打开"Authorization required"的对话框。
    1. 点击"Review Permissions"。
    2. Select自己的账号。
    3. 在 "This app isn't verified" 单击 "Advanced"。
    4. 点击"Go to ### project name ###(unsafe)"
    5. 单击 "Allow" 按钮。
  6. 点击"OK"。
  7. 复制 Web Apps 的 URL。就像 https://script.google.com/macros/s/###/exec.

    • 当您修改 Google Apps 脚本时,请重新部署为新版本。这样,修改后的脚本就会反映到 Web 应用程序中。请注意这一点。
  8. 请将上述脚本的https://script.google.com/macros/s/###/exec的URL设置为url。并请重新部署 Web 应用程序。由此,最新的脚本被反​​映到Web Apps。所以请注意这一点。

4。测试此解决方法。

请运行 2 位用户同时使用main() 的功能,正如您所测试的那样。由此发现脚本是运行独占。在我的环境中,在这种情况下,我确认即使不使用 LockService,脚本也是独占的 运行。但我想推荐使用 LockService 以防万一。

注:

  • 这是一个简单的示例脚本,用于解释此解决方法。所以大家在使用的时候,请根据自己的实际情况进行修改。
  • 关于LockService可能不会影响到Google幻灯片的情况,目前阶段,虽然我不确定这是否是bug,但向the Google issue tracker报告如何?不幸的是,我在当前的 Google 问题跟踪器中找不到这个问题。

参考文献: