Quite often there are applications where object properties need to be reflected or processed only when they change value. This is very simple to do with Limelight XE™ via several language extensions. However, first we need to discuss how the embedded scripting engine executes JavaScript code.
The ChakraCore engine is single threading and isolated from all other threads and processes... it runs in its own memory, but has access to the entire system object library.
There are several language extensions that are useful for monitoring properties for changes.
ace.getProperty()
- Immediately returns the value of an object's property.ace.getProperties()
- Immediately returns all of the object properties.ace.waitForProperty()
- Waits for a property to change and returns with the new value (timeout is optional)ace.notifyPropertyChange()
- Creates a notification task with a callback function which is executed when the object's property changes.ace.clearNotification()
- Clears a background notification task (stops the task created by notifyPropertyChange).
Looping and Checking Methods
We will discuss each method and show example code to clarify the use case. The most easy to understand is the getProperty()
and the getProperties()
functions. Both of these functions simply attempt to retrieve the value of the given property as a string.
Example using getProperty()
to monitor a single property value
// example for monitoring a property with ace.getProperty()
// uses a single global variable named Test
(()=>{ // main script begins...
// create GUID constant to global variables
const globVarGUID = '{759161EB-1005-0010-0000-000000000000}';
// clear console
console.clear();
// initialize the property value
var test = ace.getProperty(ace.this.serverGUID, globVarGUID, 'Test');
var test_current = test;
// report the current value
console.log('Test = ' + test);
// wait for it to change
while (test == test_current) {
// wait 5 seconds
ace.wait(5000);
// get the current value
test_current = ace.getProperty(ace.this.serverGUID, globVarGUID, 'Test');
}
// value has changed
console.log('Test = ' + test_current);
}
)(); // end of main script...
Example using getProperties()
to monitor multiple property values
// example for monitoring multiple properties with ace.getProperties()
// uses two global variables named Test and Test2
(()=>{ // main script begins...
// create GUID constant to global variables
const globVarGUID = '{759161EB-1005-0010-0000-000000000000}';
// clear console
console.clear();
// initialize the properties
var obj = ace.getProperties(ace.this.serverGUID, globVarGUID);
// make sure it is a valid object
if (typeof obj != 'undefined') {
// initialize
var test = obj.Test;
var test2 = obj.Test2;
var test_current = test;
var test_current2 = test2;
// report the current value
console.log('Test = ' + test);
console.log('Test2 = ' + test2);
// wait for it to change
while ((test == test_current) && (test2 == test_current2)) {
// wait 5 seconds
ace.wait(5000);
// get the current values
obj = ace.getProperties(ace.this.serverGUID, globVarGUID);
test_current = obj.Test;
test_current2 = obj.Test2;
}
// a value has changed
console.log('Test = ' + test_current);
console.log('Test = ' + test_current2);
}
else {
console.log('invalid object');
}
}
)(); // end of main script...
System Monitoring Methods
Looping to monitor each property is inefficient and will waste CPU cycles, however there may be reasons to use this method. A better approach is to let the system monitor the property for you. This is done either by initiating a "wait until the property changes" method or to start a background task that calls the code back when something changes.
Here is a simple example to wait for a single variable value to change
// example for monitoring a property with ace.waitForProperty()
(()=>{ // main script begins...
// create GUID constant to global variables
const globVarGUID = '{759161EB-1005-0010-0000-000000000000}';
// clear console
console.clear();
// get the current value
var test = ace.getProperty(ace.this.serverGUID, globVarGUID, 'Test');
// report it
console.log('Test = ' + test);
// now wait for it to change with a timeout of 10 seconds (if value changes sooner, it immediately returns)
test = ace.waitForProperty(ace.this.serverGUID, globVarGUID, 'Test', 10000);
// report current value
console.log('Test = ' + test);
}
)(); // end of main script...
This works great and can be set to wait forever by omitting the timeout value (e.g. providing only the server GUID, object GUID and property name in the call). Note that waiting is a blocking method - that is, the script will stop execution until either a timeout or the property changes. A more sophisticated method is to use call-backs. This makes it very simple to monitor multiple properties simultaneously.
Here is an example of using ace.notifyPropertyChange()
and ace.clearNotify()
functions
// example for monitoring a property with ace.notifyPropertyChange()
// create GUID constant to global variables
const globVarGUID = '{759161EB-1005-0010-0000-000000000000}';
// create a callback pass counter
var passes = 0;
// monitor two global variables named Test and Test2 - call back when either of them change value
var taskId1 = ace.notifyPropertyChange(NotifyCallback, ace.this.serverGUID, globVarGUID, 'Test');
var taskId2 = ace.notifyPropertyChange(NotifyCallback, ace.this.serverGUID, globVarGUID, 'Test2');
// return control to system to monitor for changes. Note: you can also use a timeout and loop to keep the
// script running if it needs to do other tasks. use a while(true) {} loop with a ace.wait(timeout) call to accomplish
// this function. Here, we just exit the main script which returns control to any pending tasks.
// callback function from ace.notifyPropertyChange(). Called when a property change notification is triggered.
function NotifyCallback(task_id, serverGUID, objGUID, PropName, Value) {
// report which property changed
console.log('Task ID = ' + task_id);
console.log('Server GUID = ' + serverGUID);
console.log('Object GUID = ' + objGUID);
console.log('Property Name = ' + PropName);
console.log('New Value = ' + Value);
// after 10 changes, prevent further object property changes from triggering this callback again
// (note: remove the following lines to allow indefinite notifications on object property value changes)
passes++;
if (passes >= 10) {
ace.clearNotify(task_id1);
ace.clearNotify(task_id2);
}
}