There’s a lot of questions on the the Google Apps Script forum about handling asynchronous calls from an HtmlService client back to the Server. This is done using google.script.run – but it’s important to realize that this is an asynchronous call. This means that code coming afterwards will be executed before it’s actually finished. For those used to Server side Apps Script it can be confusing. In this post I’ll show how to better orchestrate these kind of calls.

Elsewhere on my site you’ll see how I handle this with an eye to reusing the same code on the client and the server using the Provoke namespace, but for this tutorial, I’ll go back to basics with google.script.run.

Server side functions

Let’s say that you have 2 server side functions you want to call from client side. One that gets the name of all the sheets in a spreadsheet, and then gets the headings in a given sheet. The simplest way to do this would be to create a server side function that did both at the same time, however you may want to first get the list, then do something client side to choose the sheet you want, then get the headings.

First though let’s simply look at getting the sheet names in a spreadsheet.

Server side, this function is waiting to be invoked

Client side calls

And we’ll call it like this from client side. It’s important to call both the .withSuccessHandler and .withFailureHandler methods to define a function to execute in either circumstance. Here I’m simply showing the result, or the error.

I’ve linked this function with the getSheets button, and we get this result in the Sheets div.


Imagine now that we needed to select a sheet and make a second call to another server side function. It would need to happen inside the function activated by .withSuccessHandler. Here’s the second server side function

So now we have a second google.script.run pattern inside the first.

Which I’ll attach to the get headings button


Organizing with promises

But it’s starting to get a little messy. If there were other functions following on, we’d end up with a real mess – so here’s an alternative approach – using promises to tame the spaghetti, so all that could be written as simply as this

  • resolve – a function that marks the promise as resolved
  • reject – a function that marks the promise as rejected

That means I can wrap google.script.run in a function callback to a new Promise object, and my .withSuccessHandler and .withFailureHandler functions will call resolve or reject appropriately. I also pass the result and error as arguments to both resolve and reject. These are preserved in the promise so they can be retrieved later.

Arguments

Since this is a generalized function it needs to be able to receive the name of the serverside function, but also there may be arguments to deal with, so we need to find a way of passing on the arguments. JavaScript arguments arrive in a function in a special object called “arguments”. This is a kind of an array, but it doesn’t have the methods available that you find in a normal array. Arriving in my function will be at least the name of the server side function, but any number of some others, so the first task is to strip off the function name from the arguments object – that’s what’s going on here. In summary – because arguments doesn’t have a .slice method on its own, I can “borrow” the slice method from theArray prototype like this. var runArgs = Array.prototype.slice.call(arguments).slice(1); Later on, I have the opposite problem- meaning that I need to convert this array back to a an argument type object. I can use the apply method of the function to pass the arguments to the function.

Error handling

If an error happens server side, the function passed to .withFailureHandler is executed, so in the generalized promiseRun function, the .withFailure handler will call the reject() function to indicate a failed promise.

Putting it all together

Here’s the final thing

Notice that no matter how many server side functions are dependent on each other, they can simply be chained together using .then and you can be sure they will run in the correct order, as the function passed to .then is not executed until the Promise is resolved, and here is the result.

Error handling

We’ve looked at the .then method of a Promise which is executed following a successful resolution. Promises also have a .catch method which is executed following a reject. This is the mechanism for promise error handling. Another benefit is that you don’t need to handle an error at every level, which can be another source of spaghetti. Although I have a few Promises in this process, I’m only going to bother handling this at the very top level, so here’s how I assign this entire process to a button.

Parallel orchestration

So far we’ve looked at sequential operations. Promises also make it easy to control operations that can happen in parallel. That’ll be in the next post on this subject, which you’ll find here Organizing parallel streams of server calls with google.script.run promises

For more like this see Google Apps Scripts Snippets
Why not join our forum, follow the blog or follow me on Twitter to ensure you get updates when they are available.