首页 > 解决方案 > 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>

快速单击该按钮应该返回相同的数字,但它不会...

标签: asynchronousgoogle-apps-scriptweb-applicationslocking

解决方案


是的!Web 应用程序调用,如doPost()异步运行。

问题:

您无法复制冲突的原因是您的sleep 时间相对于浏览器进行 http 调用所花费的时间太短了

解决方案:

  • 增加到sleep1 分钟或更长时间。

    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>


推荐阅读