我一直在研究,找不到关于如何在Google App脚本中使用异步函数的参考或文档,我发现人们提到这是可能的,但没有提到如何... >
有人能指出我正确的方向还是给我一个例子? 承诺,回调或其他可以帮助我解决此问题的方法。
我有此函数,可以将其称为foo
,这需要花费一些时间才能执行(时间长到可能使http调用超时)。
我想做的就是重构,就像这样
function doPost(e) {
// parsing and getting values from e
var returnValue = foo(par1, par2, par3);
return ContentService
.createTextOutput(JSON.stringify(returnValue))
.setMimeType(ContentService.MimeType.JSON);
}
function foo(par1, par2, par3) {
var returnValue = something(par1, par2, par3); // get the value I need to return;
// continue in an Async way, or schedule execution for something else
// and allow the function to continue It's flow
return returnValue;
}
现在,我想意识到foo
中的那个位,因为它花了很长时间,而且我不想冒险超时,而且在那里发生的逻辑完全是与客户无关的,所以它不会事情,我只需要返回值就可以了。
另外,我认为值得一提的是,它已作为网络应用程序部署在Google Drive中。
答案 0 :(得分:4)
还有另一种方法可以完成此任务。
您可以使用time-based one-off triggers异步运行函数,它们花一些时间排队(30-60秒),但是对于要从主执行中删除的慢速运行任务是理想的选择您的脚本。
// Creates a trigger that will run a second later
ScriptApp.newTrigger("myFunction")
.timeBased()
.after(1)
.create();
我整理了一个方便的脚本,称为Async.gs
,可帮助您删除该技术的样板。您甚至可以使用它通过CacheService传递参数。
这里是链接:
https://gist.github.com/sdesalas/2972f8647897d5481fd8e01f03122805
// Define async function
function runSlowTask(user_id, is_active) {
console.log('runSlowTask()', { user_id: user_id, is_active: is_active });
Utilities.sleep(5000);
console.log('runSlowTask() - FINISHED!')
}
// Run function asynchronously
Async.call('runSlowTask');
// Run function asynchronously with one argument
Async.call('runSlowTask', 51291);
// Run function asynchronously with multiple argument
Async.call('runSlowTask', 51291, true);
// Run function asynchronously with an array of arguments
Async.apply('runSlowTask', [51291, true]);
// Run function in library asynchronously with one argument
Async.call('MyLibrary.runSlowTask', 51291);
// Run function in library asynchronously with an array of arguments
Async.apply('MyLibrary.runSlowTask', [51291, true]);
答案 1 :(得分:2)
使用新的 V8 runtime,现在可以编写 async functions 并在您的应用脚本中使用 promise。
甚至 triggers 也可以声明为异步!例如(打字稿):
async function onOpen(e: GoogleAppsScript.Events.SheetsOnOpen) {
console.log("I am inside a promise");
// do your await stuff here or make more async calls
}
要开始使用新的运行时,只需遵循此 guide。简而言之,这一切都归结为将以下行添加到您的 appsscript.json
文件中:
{
...
"runtimeVersion": "V8"
}
答案 2 :(得分:1)
不幸的是,如果我的理解是正确的,则没有直接实现它的方法和官方文档。但是,作为一种解决方法,可以同时使用Google Apps Script API和可以通过异步处理工作的fetchAll方法来实现。
此替代方法的流程如下。
如果我误解了你的问题,对不起。
答案 3 :(得分:0)
我基于Tanaike's answer创建了它的另一个版本。我的目标是:
tasks.gs
class TasksNamespace {
constructor() {
this.webAppDevUrl = 'https://script.google.com/macros/s/<your web app's dev id>/dev';
this.accessToken = ScriptApp.getOAuthToken();
}
// send all requests
all(requests) {
return requests
.map(r => ({
muteHttpExceptions: true,
url: this.webAppDevUrl,
method: 'POST',
contentType: 'application/json',
payload: {
functionName: r.first(),
arguments: r.removeFirst()
}.toJson(),
headers: {
Authorization: 'Bearer ' + this.accessToken
}
}), this)
.fetchAll()
.map(r => r.getContentText().toObject())
}
// send all responses
process(request) {
return ContentService
.createTextOutput(
request
.postData
.contents
.toObject()
.using(This => ({
...This,
result: (() => {
try {
return eval(This.functionName).apply(eval(This.functionName.splitOffLast()), This.arguments) // this could cause an error
}
catch(error) {
return error;
}
})()
}))
.toJson()
)
.setMimeType(ContentService.MimeType.JSON)
}
}
helpers.gs
// array prototype
Array.prototype.fetchAll = function() {
return UrlFetchApp.fetchAll(this);
}
Array.prototype.first = function() {
return this[0];
}
Array.prototype.removeFirst = function() {
this.shift();
return this;
}
Array.prototype.removeLast = function() {
this.pop();
return this;
}
// string prototype
String.prototype.blankToUndefined = function(search) {
return this.isBlank() ? undefined : this;
};
String.prototype.isBlank = function() {
return this.trim().length == 0;
}
String.prototype.splitOffLast = function(delimiter = '.') {
return this.split(delimiter).removeLast().join(delimiter).blankToUndefined();
}
// To Object - if string is Json
String.prototype.toObject = function() {
if(this.isBlank())
return {};
return JSON.parse(this, App.Strings.parseDate);
}
// object prototype
Object.prototype.toJson = function() {
return JSON.stringify(this);
}
Object.prototype.using = function(func) {
return func.call(this, this);
}
http.handler.gs
function doPost(request) {
return new TasksNamespace.process(request);
}
通话约定
只需使数组具有完整的函数名,其余的就是函数的参数。一切完成后它将返回,就像Promise.all()
var a = new TasksNamespace.all([
["App.Data.Firebase.Properties.getById",'T006DB4'],
["App.Data.External.CISC.Properties.getById",'T00A21F', true, 12],
["App.Maps.geoCode",'T022D62', false]
])
返回预览
[ { functionName: 'App.Data.Firebase.Properties.getById',
arguments: [ 'T006DB4' ],
result:
{ Id: '',
Listings: [Object],
Pages: [Object],
TempId: 'T006DB4',
Workflow: [Object] } },
...
]
注释