Die Google Apps Script-Web-App wird nicht wie erwartet asynchron ausgeführt

Sep 28 2020

Ich habe eine nicht blockierende Web-App (dh kein LockService), die einen in ScriptProperties gespeicherten Zähler zurückgibt.

Ich habe einen künstlichen Schlaf im Skript, um asynchrone Aufrufe der Web-App zu testen.

Wenn ich mir diesen Code unten anschaue, würde ich davon ausgehen, dass zwei aufeinanderfolgende Aufrufe der Web-App dieselbe Nummer zurückgeben sollten.

Dies ist jedoch nicht der Fall. Zwei Aufrufe der Web-App direkt nacheinander geben steigende Nummern zurück. Dies lässt mich denken, dass der erste Anruf beendet wird, bevor der zweite ausgeführt wird - was keinen Sinn ergibt.

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);
}

Ich versuche herauszufinden, wie / warum. Unterstützt Google keine asynchronen Anrufe für Web-Apps?

Sie können dies bei sehen https://script.google.com/macros/s/AKfycbxP6TQeMv_4b1lsYvGLA3YAn_reBhZ64Y2d04DotQ4CFJQtKhM/exec.

** UPDATE **

Hier ist eine lokale HTML-Datei, die ich zum Testen verwende.

<!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>

Wenn Sie sehr schnell auf die Schaltfläche klicken, wird dieselbe Nummer zurückgegeben, aber nicht ...

Antworten

4 TheMaster Sep 28 2020 at 15:46

Ja! Webanwendungsaufrufe werden gerne doPost()asynchron ausgeführt.

Problem:

Der Grund, warum Sie die Kollision nicht replizieren konnten, ist, dass Ihre sleepZeit im Vergleich zu der Zeit, die der Browser für http-Aufrufe benötigt, zu niedrig war

Lösung:

  • Erhöhen Sie sleepauf 1 Minute oder mehr.

    Utilities.sleep(1*60*1000);
    
  • Sie können Asynchronität auch leicht nachweisen, wenn Sie eine zufällige Ruhezeit mit dem folgenden Snippet-Skript verwenden, das die Zeit jeder Schleife zusätzlich zu zufälligen "callIt-Enden" anzeigt.

    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>