Async & Await

This document is a quick introduction to using the async and await syntactic sugar in CloudCode tasks and in TypeScript apps.

async and await works in CloudCode tasks (both JS and TS) and TypeScript apps. It does not work in the app logic for JavaScript apps.

Start with this interactive introduction to async & await if you are not familiar with the syntax at all.

Introduction to async and await usage

In JourneyApps many operations are asynchronous. We use async & await to handle this.

In CloudCode, your main run function should always be async:

export async function run() {
// Code here
}

Generally, database operations that query the backend are asynchronous, and needs await:

export async function run() {
    var user = await DB.user.first();
    console.log('name:', user.name);
    // This doesn't hit the database yet, so does not need `await`
    var assignment = DB.assignment.create();
    assignment.user(user);
    await assignment.save();
}

Fetch calls are also asynchronous and therefore require an await:

export async function run() {
    var response = await fetch("http://api.open-notify.org/iss-now.json");
    if(!response.ok) {
        throw new Error('Request failed: ' + response.statusText);
    }
    var body = await response.json();
    return body.iss_position;
}

If you define an async function, you also need to await on its response:

async function getLocation() {
    var response = await fetch("http://api.open-notify.org/iss-now.json");
    if(!response.ok) {
        throw new Error('Request failed: ' + response.statusText);
    }
    var body = await response.json();
        return body.iss_position;
    }
    
    export async function run() {
    var location = await getLocation();
    return {location: location};
}

Notable async operations:

someModel.first()

someQuery.toArray()
someQuery.first()
someQuery.destroyAll()
someQuery.count()

someDbObject.save()
someDbObject.destroy()
someDbObject.reload()

Getting belongs-to relationships are also async. If a chain of belongs-to lookups are performed, each one requires an await. For readable code, it is recommended to do each belongs-to lookup on a separate line. For example:

// Works, but not readable
let clientName = (await (await user.assignment()).client()).name;

// More readable
let assignment = await user.assignment();
let client = await assignment.client();
let clientName = client.name;

for loops require specific attention: someArray.forEach does not wait for async functions to complete, so it is recommend to use a for...of loop instead:

var objects = await DB.myobject.all().toArray();
for(let object of objects) {
    // ...
}

For example:

export async function run() {
// Task to recalculate the totals for all invoices
  var invoices = await DB.invoices.all().toArray();
  for(let invoice of invoices) {
    var line_items = await invoice.line_items.toArray();
    var total = 0;
    for(let line_item of line_items) {
      var product = await line_item.product();
      var price = product.price * line_item.quantity;
      total += price;
    }
    invoice.total = total;
    await invoice.save();
  }
}

Last updated