Overview
When composing scripts for Limelight XE finding errors can be challenging. Starting in version 2.2 the Limelight XE ACE engine and console have been upgraded to add debugging features which include breakpoints, stepping (into and over function calls), stack tracing and more. In this tutorial we will learn how to use the debugging features to solve some complex issues.
Prerequisites
- Limelight XE installed and activated.
- A basic proficiency in JavaScript programming.
- Completed Getting Started with Limelight XE Scripting tutorial
Debugger Overview
The integrated debugger allows script developers to break code either asynchronously or via break-points. It also allows stepping code either into or over function calls. See the controls overview below:
FUNCTION | DESCRIPTION |
---|---|
RUN | Runs the script without debugging (syntax and runtime errors are caught) |
RUN (DEBUG) | Runs the script with debugging including breakpoints and detailed stack trace |
PAUSE | Asynchronously stops the execution of the thread, indicates the line and dumps the stack |
STOP | Stops execution of the script |
STEP INTO | Steps one instruction - if executing a function, it will step one instruction into the function call |
STEP OVER | Steps one instruction - if executing a function, it will enter the function, return and stop on the next instruction |
CLEAR ALL BREAKPOINTS | Clears all breakpoints - script must be stopped to set or clear breakpoints (cannot be paused). |
Break Points
To set or remove breakpoints, click in the editor's gutter (where the line numbers appear) next to the line where you wish the break to occur. When a breakpoint is set, a red dot will appear in the gutter next to the line. To remove it, simply click the dot (or remove all of them by clicking the Clear All Breakpoints" button). When running without debugging, dots will turn gray indicating they are not active. When debugging, breakpoint dots will turn green to show active.
Lesson 1 - Using the Debugger
Using the Script Manager create a new script and rename it to 'debugging_lesson_1.js' (use the properties tab to rename the script). Next open the editor and paste the following code:
// function calculates the first 20 pime numbers
function primeNumbers() {
var primeNumbers = [], // create a structure where primes are stored
candidate = 1, // because we ++candidate in the loop we really start at 2
root,
i;
main: while (primeNumbers.length <= 20) {
++candidate;
root = Math.sqrt(candidate);
for (i = 0; i < primeNumbers.length && primeNumbers[i] <= root; ++i)
if (candidate % primeNumbers[i] === 0)
continue main; // this isn't a prime, so skip to next candidate
// if we reach here then the candidate is prime
primeNumbers.push(candidate);
}
console.log('Prime Numbers: \x1b[93m' + primeNumbers);
}
// execute the prime number function
primeNumbers();
Once the code is pasted into the editor and saved to the server, place a break-point at the call to primeNumbers()
. See below:
Now click the RUN (DEBUG) button on the toolbar. The script engine will run until it hits this breakpoint, indicate a breakpoint has occurred in the console and dump the call stack (see below).
Now continue execution by clicking the RUN (DEBUG) button on the toolbar and observe the script runs to completion (see below).
Next, clear the log and click the RUN (DEBUG) button on the toolbar again to execute to the existing breakpoint. Once the execution stops (as it did above) click the STEP INTO button on the toolbar. This will cause the script engine to begin execution of the primeNumbers() function call and stop on the first executable line within the function (see below).
Note that execution has stopped on the first instruction within the primeNumbers() function and the call stack dump indicates it has pushed the return location onto the stack. This is very helpful when trying to figure out how deep execution is into function calls.
Now continuously click either the STEP INTO or STEP OVER buttons and observe each line being executed. To continue, simply click the RUN (DEBUG) button and the execution will continue to the end and exit the execution mode.
Lesson 2 - Debugging Run Time Errors
In many cases your code will not contain syntactical errors but more subtle run-time errors such as null pointers or division by zero exceptions. These are always caught (regardless of debugging or normal execution) unless they are bracketed by a try-catch block.
Using the Script Manager create a new script and rename it to 'debugging_lesson_2.js' (use the properties tab to rename the script). Next open the editor and paste the following code and save it to the server by pressing the UPDATE button (or pressing Alt-F-S):
function calculatePercentage(x, y) {
// percentage is ratio of 2 numbers within a range of 0 - 100
// to ensure we have a valid number returned, we introduce a
// means to validate the divider is valid (non-zero for sure).
y = +y; // Coerce to number.
if (!y) { // Matches +0, -0, NaN
throw new Error('Invalid dividend: ' + y);
}
var p = (x / y) * 100;
return p;
}
// now execute and introduce a runtime error
var a = 5;
var b = 9;
var percentage = 0;
for (var i = 0; i < 11; i++) {
percentage = calculatePercentage(a, b-i);
console.log('Percentage of A:\x1b[92m%s\x1b[m and B:\x1b[92m%s\x1b[m is: \x1b[93m%s%',
a, b-i, percentage.toFixed(2));
}
Note that JavaScript will attempt to divide by zero which is mathematically undefined (a Cauchy Limit will approach infinity so that is the returned value from the attempt). To catch these errors, we introduce a test to make sure anything passed into the y parameter is valid and not zero. Also note the fancy formatting of the results sent to the console...
Next Click the RUN (DEBUG) button on the editor's toolbar. The execution will begin writing various percentage calculations to the console until it hits the invalid divide by zero (see below):
Next click RUN (DEBUG) and the script will exit with the engine also catching the run-time error.
Conclusion
Debugging scripts is an important part of development especially in very complex systems. Limelight XE's debugging capability should help developers find all kinds of errors and speed development. For more information on scripting see the useful links below.