Table of Contents

Async

Hiphop async forms enables HipHop to control (i.e., abort, suspend, resume, and react to) long lasting background JavaScript actions. They are the essential ingredient for mixing undeterministic asynchronous computations and deterministic synchronous computations. In other words, the async form enables well-behaving synchronous to regulate unsteady asynchronous computations.

async [ident] { ... } [kill { ... }] [suspend { ... }] [resume { ... }]

Formal syntax

The async form executes a JavaScript statement and upon its completion, the asynchronous block can resume the synchronous machine by calling one of the functions that compose the async JavaScript API. When an ident is specified with the async call, the JavaScript code will have the possibility to emit a signal whose name is ident when the asynchronous block completes or simply progresses.

A async statement blocks until its JavaScript body invokes the this.notify method. In other words, an async statement completes when its JavaScript body invokes the notify method.

Example

This example spawns a JavaScript timer that will complete no sooner than five seconds after being started. When the timeout is reached, the JavaScript asynchronous computation resumes the reactive machine and emit the signal O with the value 5.

Inside the asynchronous block, the JavaScript this object is a descriptor of the asynchronous computation. The machine that has spawned this async form is stored in this.machine.

Example exec2.hh.js

import * as hh from "@hop/hiphop";

hiphop module prg(resolve) {
   out O;
   async (O) {
      setTimeout(() => this.notify(5), 100);
   }
   pragma { resolve(false); }
}

export const mach = new hh.ReactiveMachine(prg, "exec");
mach.outbuf = "";
mach.addEventListener("O", function(evt) {
   mach.outbuf += ("O emitted!") + "\n";
});
mach.debug_emitted_func = val => val;
mach.batchPromise = new Promise((res, rej) => mach.init(res));

mach.react();

Kill, suspend, and resume

The optional arguments kill, suspend, and resume are JavaScript statements that are executed when the HipHop statement state changes. They give the opportunity to the JavaScript program to cleanup a computation if the async block is preempted or suspended or resumed.

The following example shows a JavaScript setTimeout that is stopped when the HipHop async statement is aborted.

Example exec-susp-res.hh.js

import * as hh from "@hop/hiphop";
import { format } from "util";

let glob = 5;

hiphop module prg(resolve) {
   in RESS; in S; out O; out OT; in T;
   fork {
      suspend (S.now) {
         async (T) {
            mach.outbuf += "Oi.\n";
            setTimeout(function(self) {
               mach.outbuf += "Oi timeout.\n";
               self.notify(glob++, false);
            }, 100, this);
         } suspend {
            mach.outbuf += "suspended.\n";
         } resume {
            mach.outbuf += "resumed.\n";
         }
      }
   } par {
      emit O();
   }

   await (RESS.now);
   emit OT(T.nowval);
   pragma { resolve(false); }
}

export const mach = new hh.ReactiveMachine(prg, "exec");
mach.outbuf = "";
mach.debug_emitted_func = emitted => {
   mach.outbuf += format(emitted) + "\n";
}
mach.batchPromise = new Promise((res, rej) => mach.init(res));

mach.react();
mach.inputAndReact("S");
mach.inputAndReact("S");
mach.inputAndReact("S");
mach.inputAndReact("S");
mach.react();
mach.react();
mach.inputAndReact("S");

setTimeout(function() {
   mach.react();
   mach.react();
   mach.inputAndReact("RESS");
   mach.inputAndReact("S");
   mach.react();
}, 100);

Async JavaScript API

JavaScript asynchronous blocks can use several functions to notify the reactive machine that their state have changed.

Inside the body of an async form, this is bound to an async descriptor and the reactive machine executing asynchronous block is to be found in this.machine. New reactions can be triggered from within the async JavaScript block. Example:

Example setinterval.hh.js

import * as hh from "@hop/hiphop";
import { format } from "util";

hiphop module setinterval(resolve) {
   inout A, Tick;
   fork {
      abort count(3, Tick.now) {
         async (A) {
            this.tmt = setInterval(() => this.react(Tick.signame), 100);
         } kill {
            clearInterval(this.tmt);
         }
      }
   }
   pragma { resolve(false); }
};
   
export const mach = new hh.ReactiveMachine(setinterval);

mach.outbuf = "";
mach.debug_emitted_func = val => {
   mach.outbuf += format(val) + "\n";
}
mach.batchPromise = new Promise((res, rej) => mach.init(res));

mach.react();

This example uses the expression Tick.signame that is a JavaScript expression that evaluates to the HipHop internal name of the signal Tick.

async.notify(value, [react = true])

This function notifies the reactive machine that the async form has completed and it emits the event that was associated with the form.

 

Notifying the termination of the async form with the method notify is not equivalent to triggering a new reaction as only the notify method tells HipHop to execute the next statement in sequence.

How and when the machine is notified depends of value's type. Two cases are considered:

Here is an example of an async block that uses a JavaScript Promise to resume the HipHop computation.

Example exec3.hh.js

import * as hh from "@hop/hiphop";
import { format } from "util";

hiphop module prg(resolve) {
   out O;
   async (O) {
      this.notify(new Promise(function(resolve, reject) {
         setTimeout(() => resolve(5), 100);
      }));
   }
   pragma { resolve(false); }
}

export const mach = new hh.ReactiveMachine(prg, "exec");

mach.addEventListener("O", function(evt) {
   mach.outbuf += ("O=" + evt.nowval.val + " emitted!") + "\n";
});
mach.batchPromise = new Promise((res, rej) => mach.init(res));
mach.debug_emitted_func = val => val;

mach.outbuf = "";
mach.react();

The optional argument react controls whether a reaction should be automatically triggered with the notification. If the react is true, a reaction to the machine is executed. The following asynchronous block:

async {
   this.notify("complete");
}

is equivalent to:

async {
   this.notify("complete", false);
   this.react();
}

async.react(sigset)

Invokes the react method with sigset argument of the machine running the async block.


[main page] | [documentation] | [language] | [license]