T
Thierry Ciot
Guest
Introduction
When integrating a Progress Corticon decision service into your JavaScript applications, handling asynchronous (async) operations correctly is critical, as decision services are an async function.
This blog presents three common async invocation patterns—using async/await propagation, a synchronous facade with an immediately invoked async function (IIAFE) and Promise chaining with .then()—all wrapped in a simple event-driven design that notifies when the decision service completes.
These patterns are demonstrated in this sample on the Corticon public Github.
As a historical note, decision services became asynchronous when we introduced support for service callout in Corticon V2.0.
The Heart of the Integration: runDecisionService
Before we dive into the patterns, let’s look at the core async function that executes the Corticon rules engine—a common element to the three patterns presented below:
Code:
async function runDecisionService() {
try {
…
// Await the async decision service execution
const result = await window.corticonEngine.execute(payload, configuration);
…
} catch (e) {
alert('Unexpected exception executing the rules: ’ + e);
throw e;
}
}
This function uses modern async/await for clean, readable asynchronous calls and implements error handling. The code reads sequentially, and the execution is also sequential. That is, this function will return when the decision service has completed.
Three Ways to Invoke the Decision Service
1. Async/Await Propagation — Async All the Way
You typically have a call stack of functions executing before the decision service is invoked. In this sample, we illustrate this condition with f1() calling f2() calling runDecisionService.
Code:
async function f1() {
console.log(“In f1 (async)”);
await f2();
}
async function f2() {
console.log(“In f2 (async)”);
await runDecisionService();
}
How it works:
- Each function in the call stack is declared async
- Each awaits the next, creating a clear, sequential flow that reads
synchronously - Errors propagate naturally via try/catch
Pros:
- Clean, readable code
- Easy error handling
- Modern JavaScript best practice
Cons:
- Requires async propagation throughout the call chain, which can be
intrusive in legacy or synchronous-heavy codebases - Main thread is blocked until the decision service has completed
(typically, decision services execute very fast, but if yours is
blocking the UI too long you may want to consider the options below)
2. Synchronous Facade with an IIAFE
Code:
function f1Sync() {
console.log(“In f1Sync (sync)”);
f2Sync();
console.log(“Exiting f1Sync before decision service completes”);
}
function f2Sync() {
console.log(“In f2Sync (sync)”);
(async () => {
console.log(“Invoking decision service inside IIAFE”);
const result = await runDecisionService();
console.log(“Decision service completed inside IIAFE”);
eventEmitter.emit(‘dsDone’, result);
})();
}
How it works:
- The main call stack remains synchronous
- Async logic runs inside IIAFE
- f2Sync() returns immediately, but the async call happens in the background
- Upon completion, a custom event (dsDone) is emitted to notify listeners
Pros:
- Integrates async operations without marking all callers async
- Keeps synchronous APIs intact
- UI not “frozen” until decision service completes
- Event-driven design lets other parts of the app respond when the decision service completes
Cons:
- Callers don’t get the async result directly (must listen for events)
- Slightly more complex pattern to understand initially
3. Promise Chaining with .then()
Code:
function f1SyncWithThen() {
console.log(“In f1SyncWithThen (sync)”);
f2SyncWithThen();
console.log(“Exiting f1SyncWithThen before decision service completes”);
}
function f2SyncWithThen() {
console.log(“In f2SyncWithThen (sync)”);
console.log(“Invoking decision service with .then()”);
runDecisionService()
.then(result => {
console.log(“Decision service completed with .then()”);
eventEmitter.emit(‘dsDone’, result);
})
.catch(error => {
console.error(“Error in decision service (with .then()):”, error);
alert("Error executing the decision service: " + error);
});
console.log(“Proceeding after invoking decision service with .then()”);
}
How it works:
- The call stack remains synchronous
- Uses Promise chaining (.then()) to handle async results
- Emits an event upon completion
- Includes error handling via .catch()
Pros:
- Familiar pattern for Promise handling
- Works well in environments without async/await
- Easy to add error handling
Cons:
- Slightly less readable than async/await
- Can become nested with multiple async steps
Event-Driven Notifications
The sample on the Corticon public Github page also introduces a simple EventEmitter to allow your app to respond when the decision service completes:
Code:
class EventEmitter {
constructor() { this.events = {}; }
on(event, listener) {
if (!this.events[event]) this.events[event] = [];
this.events[event].push(listener);
return this;
}
emit(event, …args) {
if (!this.events[event]) return false;
this.events[event].forEach(listener => listener(…args));
return true;
}
}
const eventEmitter = new EventEmitter();
// Listen for decision service completion event
eventEmitter.on(‘dsDone’, (result) => {
console.log(“Event: Decision Service Completed”);
// Further UI updates or workflows can be triggered here
});
This pattern decouples your UI or business logic from the async decision service invocation, promoting clean separation and easier maintenance.
Choosing the Approach that Works for You
Here is a table summarizing the pros and cons of the patterns as presented in the sample on the Corticon public Github page:
Pattern | When to Use | Pros | Cons |
Async/Await Propagation | New projects or full async control | Readable, linear flow; easy error handling | Async "coloring" spreads through code |
Synchronous Facade (IIAFE) | Integration into legacy or synchronous APIs | Keeps call stack sync; event notifications | More complex; no direct return values |
Promise Chaining (.then()) | Preferring classic Promises or older envs | Familiar; works everywhere | Less readable with multiple async steps |
Take the next step and enroll in free training, or learn more about Corticon.js.
Continue reading...