Table of Contents

Async

Async forms implement long lasting background Hop (i.e., JavaScript) actions. They are the essential ingredient for mixing undeterministic asynchronous computation 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 execute a JavaScript statement that is supposed to spawn a long lasting background computation. When this complete, the asynchronous block can resume the synchronous machine by calling the function that composes the async JavaScript API. When an ident is specified with the async call, the JavaScript will have the possible to emit a signal whose name is ident when the asynchronous block completes or simply progresses.

Example

This example spawns a JavaScript timer that will completes no sooner than five seconds after being started. When the timeout is reached, that 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.

exec2.hh.js

"use hiphop"
"use hopscript"

const hh = require( "hiphop" );

hiphop module prg( O ) {
   async O {
      setTimeout( () => this.notify( 5 ), 3000 );
   }
}

var machine = new hh.ReactiveMachine( prg, "exec" );

machine.addEventListener( "O", function( evt ) {
   console.log( "O emitted!" );
} );

machine.react();

Kill, suspend, and resume

The optional arguments kill, suspend, and resume of async blocks are JavaScript statements that are executed when the HipHop statement state changes. They give the opportunity to the program to cleanup a computation if the async block is preempted or to suspend/resume it. It is up to JavaScript to stop and to free resources if needed.

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

local-kill2.hh.js

"use hiphop";
"use hopscript";

const hh = require( "hiphop" );

const mach = new hh.ReactiveMachine(
   hiphop module( A ) {
      T: fork {
         loop {
            let tmt;

            async {
               tmt = setTimeout( this.notify.bind( this ), 1000 );
            } kill {
               console.log( "killed" );
               clearTimeout( tmt );
            }

            hop { console.log( 'tick 10s' ) }
         }
      } par {
         async {
            setTimeout( this.notify.bind( this ), 50 );
         }
         break T;
      }

      emit A();
   } );

mach.debug_emitted_func = console.log;

mach.react();

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 the instance of the currently executing asynchronous block. The current machine executing that statement is retrieved with this.machine.

New reactions can be spawned from with a. async block. Example:

"use hiphop";
"use hopscript";

const hh = require( "hiphop" );

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

mach.debug_emitted_func = console.log;

mach.react();

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

This function notifies the reactive machine that the async form has completed.

This function notifies the reactive machine that the async form has completed and it emits the event that was associated with the form. 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.

exec3.hh.js

"use hiphop"
"use hopscript"

const hh = require( "hiphop" );

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

var machine = new hh.ReactiveMachine( prg, "exec" );

machine.addEventListener( "O", function( evt ) {
   console.log( "O=" + evt.nowval.val + " emitted!" );
} );

machine.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.

Inside an async block, the expression:

this.react( sigset )

is equivalent to:

this.machine.react( sigset )