【问题标题】:Is google apps script synchronous?谷歌应用脚​​本是同步的吗?
【发布时间】:2015-09-23 08:05:27
【问题描述】:

我是一名 Java 开发人员,同时学习 JavaScript 和 Google Apps 脚本。作为新手,我学习了 JavaScript 的语法,而不是它的实际工作原理,我很高兴地在 Google Apps Script 中破解并编写了顺序和同步的代码,就像 Java 一样。我所有的代码都是这样的:(大大简化以表明我的意思)

function doStuff() {
  var url = 'https://myCompany/api/query?term<term&search';
  var json = getJsonFromAPI(url);
  Logger.log(json);
}

function getJsonFromAPI(url) {
  var response  = UrlFetchApp.fetch(url);
  var json = JSON.parse(response);
  return json;
}

而且它有效!它工作得很好!如果我不继续学习 JavaScript,我会说它就像发条一样工作。但是 JavaScript 不是发条,它是非常异步的,据我了解,这根本不应该工作,它会“编译”,但记录 json 变量应该记录未定义,但它记录 JSON 没有问题。

注意:

代码在 Google Sheet 的脚本编辑器中编写和执行。

这是为什么?

【问题讨论】:

标签: javascript google-apps-script v8


【解决方案1】:

虽然 Google Apps 脚本 implements a subset of ECMAScript 5,但并没有强制它是异步的。

虽然 JavaScript 的主要力量确实在于其异步特性,但 Google 开发人员似乎已经放弃了这一点,转而支持更简单、更直接的 API。

UrlFetchApp 方法是同步的。它们返回一个HttpResponse 对象,并且它们不接受回调。显然,这是一个 API 决定。

【讨论】:

  • 但是为什么我所有的方法都是按顺序执行的呢?记录器不应该在getJsonFromAPI() 完成执行之前记录 JSON 吗? (运行HttpFetchApp需要20秒左右。Aslo,GAS应该是运行V8引擎的,为什么和node不一样?
  • 您的 getJsonFromAPI() 函数不执行任何异步操作。里面所有的函数调用都是同步调用。因此,它也是同步的。
  • 我已经阅读了很多 API,但是我找不到任何可以告诉我它是同步还是异步的东西,您介意将我链接到您的源吗?
  • 无需指定。如果没有返回承诺或接受回调,任何api都不能是异步的,就这么简单。
  • 这也让我一时糊涂了。现在我明白了
【解决方案2】:

请注意,自 introduction of V8 runtime for google app scripts 以来,这并没有真正改变。

当我们使用最新最好的 ECMAScript 版本时,运行 Promise.all(func1, func2) 我可以看到第二个函数中的代码在第一个函数完成之前不会执行。

此外,仍然没有setTimeout() 全局函数可用于分支执行顺序。任何 API 也不提供回调函数或类似 Promise 的结果。似乎 GAS 的发展理念是让一切同步。

【讨论】:

  • 他们发布了 v8 很奇怪,并且仍然在他们的 ES6 实现中使用这种奇怪的非异步方法。这是他们实现与真正的 ES6 完全平等的机会。
【解决方案3】:

我从 Google 的角度猜测,并行处理两个任务(例如,仅具有 Utilities.sleep(3000) 的任务)将需要在服务器 cpu 中运行多个线程,这可能无法管理并且可能很容易滥用。

而客户端或其他公司服务器(例如 Node.js)上的并行处理取决于该开发人员或用户。 (如果它们不能很好地扩展,那不是 Google 的问题)

但是有些东西使用了并行性


UrlFetchApp.fetchAll

UrlFetchApp.fetchAll() 将异步获取许多 url。虽然这不是您真正想要的,但获取 url 是寻求并行处理的主要原因。

我猜 Google 认为这没问题,因为 fetchall 正在使用 Web 客户端,并且它自己的资源已经受到配额的保护。


FirebaseApp 获取所有数据

与使用电子表格进行数据存储相比,我发现 Firebase 的速度非常快。你可以使用FirebaseApp's getAllData一次从数据库中获取很多东西:

function myFunction() {
  var baseUrl = "https://samplechat.firebaseio-demo.com/";
  var secret = "rl42VVo4jRX8dND7G2xoI";
  var database = FirebaseApp.getDatabaseByUrl(baseUrl, secret);

  // paths of 3 different user profiles
  var path1 = "users/jack";
  var path2 = "users/bob";
  var path3 = "users/jeane";

  Logger.log(database.getAllData([path1, path2, path3]));
}

HtmlService - IFrame 模式

HtmlService - IFrame mode 允许完全多任务处理,方法是转到真正支持 Promise 的客户端脚本并将并行调用返回到服务器。您可以从服务器启动此过程,但由于所有并行任务的结果都在客户端返回,因此不清楚如何将它们返回到服务器。您可以进行另一个服务器调用并发送结果,但我认为目标是将它们返回到首先调用 HtmlService 的脚本,除非您使用 beginRequestendRequest 类型架构。


tanaikech/RunAll

这是一个仅使用原生 Google Apps 脚本 (GAS) 运行并发处理的库。该库通过RunAll.Do(workers) 方法声称完全支持。


如果我发现任何其他技巧,我会更新我的答案。

【讨论】:

  • 您可能会发现这个answer 很有用。
猜你喜欢
  • 2015-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-19
  • 1970-01-01
  • 1970-01-01
  • 2016-10-08
  • 1970-01-01
相关资源
最近更新 更多