谷歌应用脚本是同步的吗?

20

我是一名Java开发人员,同时学习JavaScript和Google Apps Script。作为一个新手,我只是学习了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变量应该记录undefined,但却可以记录JSON而没有问题。

注意:

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

为什么呢?


相关链接:https://stackoverflow.com/a/58070370/ - TheMaster
3个回答

27

你的getJsonFromAPI()函数没有任何异步操作。所有内部的函数调用都是同步调用。因此,它也是同步的。 - Madara's Ghost
我在代码中有其他以纯JS方式运行的函数,它们也按预期运行。但是我认为谷歌的整个GAS都是同步的?因此,我的代码将作为具有JavaScript语法的Java正常工作? - Gemtastic
1
我已经阅读了很多API,但是我找不到任何关于它是同步还是异步的信息,你能否把你的源链接发给我? - Gemtastic
7
如果API不返回Promise或接受回调函数,那么它就无法异步运行,这很简单。不需要特别说明。 - Zig Mandel
2
这也让我困惑了一段时间。现在我明白了。 - 0xh8h
显示剩余2条评论

16
请注意,自引入V8运行时以来,这一点并没有真正改变。
虽然我们使用的是最新和最好的ECMAScript版本,在运行Promise.all(func1, func2)时,我发现第二个函数中的代码直到第一个函数完成后才会执行。
此外,仍然没有setTimeout()全局函数可以用来分支执行顺序。也没有任何API提供回调函数或类似promise的结果。看起来GAS的工作哲学是使所有内容都同步化。

6
他们发布了v8版本却仍然使用这种奇怪的非异步方法来实现ES6。这是他们实现与真正的ES6完全相等的机会。 - DarkNeuron

5

从谷歌的角度来看,我猜测并行处理两个任务(例如,只有Utilities.sleep(3000))需要多个线程在服务器CPU上运行,这可能是不可管理的,并且容易被滥用。

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

但是,有一些东西使用并行性。


UrlFetchApp.fetchAll

UrlFetchApp.fetchAll() 可以异步获取多个 URL。虽然这不是你真正想要的,但获取 URL 是寻求并行处理的主要原因之一。

我猜 Google 的理由是可以使用 Web 客户端的 fetchall 已经受到配额保护,所以这样做是可以的。


FirebaseApp getAllData

我发现Firebase在数据存储方面比使用电子表格要快得多。您可以使用{{link1:FirebaseAppgetAllData}}一次从数据库中获取许多内容:

function myFunction() {
  var baseUrl = "https://samplechat.firebaseio-demo.com/";
  var secret = /* your secret */;
  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 模式 允许通过客户端脚本进行完全的多任务处理,其中真正支持Promise并进行并行调用返回到服务器。您可以从服务器启动此过程,但由于所有并行任务的结果都在客户端返回,因此不清楚如何将它们返回到服务器。您可以发起另一个服务器调用并发送结果,但我认为目标是将它们返回到首先调用 HtmlService 脚本中,除非采用 beginRequestendRequest 类型的架构。


tanaikech/RunAll

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


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

1
你可能会发现这个答案很有用。 - TheMaster
我不太同意你的第一段,因为大多数现代JS运行时都有一个事件循环,它添加了(另一层)“虚假的多任务处理”。例如,fetch()发送请求,然后在响应返回之前没有**额外的操作 - PoolloverNathan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接