Search code examples
javascriptgoogle-apps-scriptweb-applications

Google Apps Script Webapp async loading


I am writing a webapp using Google Apps Script.

To reduce loading times I let doGet(e) load a small file with some javascript to asynchronously load other JS and CSS.

Loading external resources works fine of course:

<head>
  <!-- loading external resources works fine of course -->
  <script src="https://cdnjs.cloudflare.c[...]/jquery.min.js"></script>
  <link rel="stylesheet" href="https://cdnjs.clou[...].1/jquery-ui.min.css">
</head>

But from what I know this cannot be done with code inside my apps script project because I cannot provide a direct link to the file. That's why I add a little <script>:

function loadScript(filePath) {
  google.script.run.withSuccessHandler(function(returnedValueFromGAS) {
    $('body').append(returnedValueFromGAS);
  }).loadScript(filePath);

  loadScript('someScriptFilepath');
  loadScript('someStyleFilepath')
}

In this manner I add <script> and <style> tags to my HTML. And I would like to have not one callback for every loaded file, but one callback when all my (script-)files are loaded.

This works fine so far with one major drawback: The Window-Load-Event is not of any use anymore.

How can I load JS and CSS files in the <head> like I would do in other environments so that the load-event still is of use for me?


Solution

  • And I would like to have not one callback for every loaded file, but one callback when all my (script-)files are loaded.

    Issue/Solution:

    • The script is calling server functions one by one, instead of one after another(or one inside another). You should nest callbacks('Callback hell') or use promises/async/await.

    Snippet:

    /**
     * Create a promise around old callback api
     * @param {String} func The server function to call
     * @param {Object} args The arguments to the server function 
     * @return Promise 
     */
    const GSR = (func,...args) => 
      new Promise((resolve,reject)=>
        google.script.run
            .withSuccessHandler(resolve)
            .withFailureHandler(reject)[func](...args)
      );
    
    const bodyAppend = function(returnedValueFromGAS) {
        $('body').append(returnedValueFromGAS);
    }
    
    //call GSR and append 
    const GSRa = (func, ...args) => 
        GSR(func, ...args)
          .then(bodyAppend)
          .catch(e=>console.error(e.message));
    
    function loadScriptClient() {//modified
      //Can also use async/await here
      Promise.all([GSRa('loadScript','someScriptFilepath'), GSRa('loadScript','someStyleFilepath')])
        .then(/*All Files loaded and appended at this point; Provide a final callback function here*/)
        .catch(e=>console.error(e.message));
    }
    

    References: