V8 Javascript API

Asynchronous Execution

[Commands]

Description

Commands can make use of all the asynchronous functionality that JavaScript and RealityServer modules provide. This includes Promises, async/await and the asynchronous fs.async and http.async modules. There is no provision to actually execute commands asynchronous however as this would break the guarantee that command sequences are executed in order. You can still execute commands in the resolve/reject functions of Promises though, with some restrictions.

There is one requirement when using asynchronous functionality which is that the command must return a Promise. That promise must not resolve or reject until all asynchronous behaviour is completed. This is to ensure that the JavaScript runtime keeps executing and runs the asynchronous code to completion.

Restrictions

It is currently not possible to call V8 implemented commands from the then/catch/finally handler of a Promise (this includes after an await expression). An error will be thrown if this is attempted. Calling C++ implemented commands is fully supported (as long as they don't themselves then call V8 implemented commands).

Example

The following shows how to use the asynchronous http module to download an image from the Internet and use it as a texture. This makes use of Promise chaining to resolve the download and create the texture.

‎const Texture = require('Texture');
const Image = require('Image');

module.exports.command = {
    name: 'download_texture',
    description: 'Downloads an image and makes a texture from it.',
    arguments: {
        texture_name: {
            description: 'The name of the texture to create.',
            type: 'String'
    }},
    execute: function({texture_name}) {
        // Download the migenius logo and create a texture out of it
        return http.async.get({
                url: 'https://www.migenius.com/migenius/wp-content/uploads/2013/04/toplogo.png',
                encoding: null
            }).then(response => {
                // error checking
                if (response instanceof http.Error) {
                    throw new RS.Error(response.code,response.message);
                }
                if (response.code !== 200) {
                    throw new RS.Error(response.code,response.message);   
                }
                // all good, create an image and texture
                const image = new Image(texture_name + '_image',true);
                // Create the texture
                const texture = new Texture(texture_name,true);

                // decode the PNG and set it on the image
                image.canvas = Canvas.decode(response.body,'png');

                // apply the image to the texture
                texture.image = image;
            });
    }
};

Alternatively, the execute function can use async/await to implement a more linear workflow:

‎const Texture = require('Texture');
const Image = require('Image');

module.exports.command = {
    name: 'download_texture',
    description: 'Downloads an image and makes a texture from it.',
    arguments: {
        texture_name: {
            description: 'The name of the texture to create.',
            type: 'String'
    }},
    execute: async function({texture_name}) {
        // Download the migenius logo and create a texture out of it
        const response = await http.async.get({
                url: 'https://www.migenius.com/migenius/wp-content/uploads/2013/04/toplogo.png',
                encoding: null
            });
        // error checking
        if (response instanceof http.Error) {
            throw new RS.Error(response.code,response.message);
        }
        if (response.code !== 200) {
            throw new RS.Error(response.code,response.message);   
        }
        // all good, create an image and texture
        const image = new Image(texture_name + '_image',true);
        // Create the texture
        const texture = new Texture(texture_name,true);

        // decode the PNG and set it on the image
        image.canvas = Canvas.decode(response.body,'png');

        // apply the image to the texture
        texture.image = image;
    }
};