asynchronous - Google Apps 脚本网络应用程序未按预期异步运行
问题描述
我有一个非阻塞(即没有 LockService)网络应用程序,它返回一个存储在 ScriptProperties 中的计数器。
我在脚本中有一个人工睡眠来测试对网络应用程序的异步调用。
查看下面的这段代码,我假设对 web 应用程序的两次连续调用应该返回相同的数字。
但是,事实并非如此。对网络应用程序的两次调用,一个接一个,返回越来越多的数字。这让我认为第一个调用在第二个调用之前完成——这没有意义。
function doGet(e)
{
// get script properties
var scriptProperties = PropertiesService.getScriptProperties();
// get ID
var id = parseInt(scriptProperties.getProperty("id"));
// fake a long process
// enough time to make another call to the web-app
// in theory, the second call will get the same value for `id`
Utilities.sleep(5000);
// write a new value
scriptProperties.setProperty("id", id + 1);
// return it
return ContentService.createTextOutput(id);
}
我试图弄清楚如何/为什么。Google 不支持对网络应用程序的异步调用吗?
您可以在https://script.google.com/macros/s/AKfycbxP6TQeMv_4b1lsYvGLA3YAn_reBhZ64Y2d04DotQ4CFJQtKhM/exec看到这个运行。
** 更新 **
这是我用来测试的本地 HTML 文件。
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script type="text/javascript">
function doIt()
{
console.log("doIt: start");
setTimeout(callIt, 500);
console.log("doIt: end");
}
function callIt()
{
console.log("callIt: start");
var request = new XMLHttpRequest();
request.open('GET', 'https://script.google.com/macros/s/AKfycbxP6TQeMv_4b1lsYvGLA3YAn_reBhZ64Y2d04DotQ4CFJQtKhM/exec', true);
request.onload = function()
{
if(this.status >= 200 && this.status < 400)
{
document.querySelector("#output").innerText += this.response + ", ";
}
else
{
alert("error");
}
};
request.onerror = function()
{
alert("error");
};
request.send();
console.log("callIt: end");
}
</script>
</head>
<body>
output:
<div id="output"></div>
<input type="button" value="Click me" onclick="doIt()">
</body>
</html>
快速单击该按钮应该返回相同的数字,但它不会...
解决方案
是的!Web 应用程序调用,如doPost()
异步运行。
问题:
您无法复制冲突的原因是您的sleep
时间相对于浏览器进行 http 调用所花费的时间太短了
解决方案:
增加到
sleep
1 分钟或更长时间。Utilities.sleep(1*60*1000);
您还可以轻松地证明异步性,如果您使用以下代码段脚本的随机睡眠时间,除了随机“callIt end”之外,它将显示每个循环的时间。
Utilities.sleep(Math.floor(Math.random()*60000)+1);
/*<ignore>*/console.config({maximize:true,timeStamps:false,autoScroll:true});/*</ignore>*/
function callIt(i) {
const label = 'callIt' + i;
console.log(label + ' start');
console.time(label);
const request = new XMLHttpRequest();
request.open(
'GET',
'https://script.google.com/macros/s/AKfycbxP6TQeMv_4b1lsYvGLA3YAn_reBhZ64Y2d04DotQ4CFJQtKhM/exec',
true
);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
console.log(this.response + `- ${label}`);
console.log(label + ' end');
console.timeEnd(label);
console.log('\n')
} else {
alert('error');
}
};
request.onerror = function() {
alert('error');
};
request.send();
}
let i = 0;
while (++i < 10) callIt(i);
<!-- https://meta.stackoverflow.com/a/375985/ --> <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
推荐阅读
- python - 在以下场景中实施 __new__ 方法时需要帮助
- python - 将 boost::python::numpy::ndarray 作为 boost::python 函数的(默认与否)参数传递?
- java - docker-java 使用 -rm 标志运行容器
- php - 展平多维数组,同时从每个数组中删除一个元素
- linux - 我正在尝试将文件从远程服务器复制到本地计算机
- bash - 从文件中选择模式并将其复制到适当位置的另一个文件
- php - 如何将一个变量的值绑定到php中的另一个变量
- apache-zookeeper - Zookeeper 超时后未恢复
- vue.js - 如何激活 Vue-Cli 4 的源映射?
- javascript - 如果复选框为真,则在文本区域中显示值