Asynchronous Event Chaining with bind
Before we get into the dedicated functions for composing multiple timelines (which will be discussed later), let’s first see how we can orchestrate a series of operations using the core features of Timeline, especially TL.bind. This is particularly useful for asynchronous event chains. This approach achieves a similar effect to JavaScript’s Promise.then chain but is realized using only the basic features of Timeline without needing additional composition functions. Understanding this fundamental capability of bind provides valuable insight into the inherent power and flexibility of the Timeline library’s design.
bind chain
Section titled “bind chain”Key Mechanisms
Section titled “Key Mechanisms”This asynchronous chain is composed of the following three key mechanisms:
- Pre-defined Receiving Timelines:
Timelineinstances (step1,step2,step3, etc.) are pre-defined to receive the results of each step. bindChain: An asynchronous operation is initiated within eachbindfunction. When that operation completes, the result is set to theTimelinefor the next step using.define().- Chain Reaction: When the value of a
Timelineis updated, the nextbindthat depends on thatTimelineis automatically triggered, and the chain progresses.
Code Example Flow
Section titled “Code Example Flow”// Similar implementation image in JavaScriptconst step0 = Timeline(null);const step1 = Timeline(null);const step2 = Timeline(null);const step3 = Timeline(null);
const asyncChain = step0 .bind(value => { // Start asynchronous operation 1 setTimeout(() => { const result1 = value + " -> The"; step1.define(Now, result1); // Trigger the next step }, 2000); return step1; // Return the Timeline for the next step }) .bind(value => { // Start asynchronous operation 2 setTimeout(() => { const result2 = value + " -> Sequence"; step2.define(Now, result2); }, 3000); return step2; }) .bind(value => { // Start asynchronous operation 3 setTimeout(() => { const result3 = value + " -> Done!!"; step3.define(Now, result3); }, 1000); return step3; });
// Start the chainstep0.define(Now, "Hello!");Comparison with Promise.then
Section titled “Comparison with Promise.then”This Timeline bind chain is similar to Promise.then in many ways.
-
Sequential Execution: The next operation starts after the previous one is complete.
-
Value Passing: The result of the previous step is passed to the next step.
However, there are also important differences in the fundamental approach.
-
Reactive:
Timelineis a reactive system that automatically triggers subsequent operations in response to value changes. -
Explicit Receiving Timeline: You need to pre-define a dedicated
Timelineto receive the result of each step. -
Synchronous Return Value: The
bindfunction itself must synchronously return theTimelineto wait for next, without waiting for the asynchronous operation to complete.
Using nBind: Towards a More Robust Chain
Section titled “Using nBind: Towards a More Robust Chain”The code example above is a “happy path” where all asynchronous operations succeed. However, in a real application, you must also consider the possibility of failure due to communication errors or unexpected results. This is where nBind is useful.
The current code using bind has a vulnerability where if any step returns null, a subsequent operation will cause an error, crashing the entire application.
bind (Original) | nBind (Refined) | |
|---|---|---|
| Happy Path | Works correctly | Works correctly |
null occurs midway | Crashes with a runtime error 💀 | Safely skips subsequent operations ✨ |
| Robustness | Low | High |
| Code Appearance | Almost the same | Almost the same |
nBind is designed to solve this problem elegantly. The operational rule of nBind is “if the input is null, pass null through without executing the subsequent function.” By simply replacing bind with nBind, you can give this asynchronous chain robustness without changing the code’s structure at all.
In comparison with Promise.then, using nBind significantly enhances the aspect of “error handling”. Unlike a Promise, which catches errors in a .catch() block, nBind propagates null as a “failure” signal safely through the pipeline without destroying it.
Code Refined with nBind
Section titled “Code Refined with nBind”const step0 = Timeline(null);const step1 = Timeline(null);const step2 = Timeline(null);const step3 = Timeline(null);
const asyncChain = step0 .nBind(value => { // .bind -> .nBind // Start asynchronous operation 1 setTimeout(() => { const result1 = value + " -> The"; step1.define(Now, result1); }, 2000); return step1; }) .nBind(value => { // .bind -> .nBind // Start asynchronous operation 2 setTimeout(() => { // Assume it fails and returns null const result2 = null; step2.define(Now, result2); }, 3000); return step2; }) .nBind(value => { // .bind -> .nBind // This function will not be executed! console.log("This will not be executed."); setTimeout(() => { const result3 = value + " -> Done!!"; // No error will occur step3.define(Now, result3); }, 1000); return step3; });
// Start the chainstep0.define(Now, "Hello!");
// The final value of asyncChain will be null, without causing an errorConclusion
Section titled “Conclusion”Using nBind is not just about replacing bind. It means refining the code to be more reliable and declarative, taking into account not only the success case but also the failure case (null). This eliminates the need to write imperative error handling like try-catch or if (value !== null) outside the pipeline, allowing you to focus on the essential flow of the code.
JS Demo
Section titled “JS Demo”
I’ve created a terminal-style demo for the Timeline Bind Chain! This demo has the following features:
Key Features
Section titled “Key Features”- Real-time Log Display: Timestamped logs for each step
- Progress Bar: Visual representation of the chain’s progress
- 3-Stage Asynchronous Process: A chain of delays: 2s → 3s → 1s
- Custom Input: Test with any initial value
Chain Flow
Section titled “Chain Flow”- Step 0: Triggered with an initial value
- Step 1: Adds ”→ Processing” after 2 seconds
- Step 2: Adds ”→ Enhanced” after 3 seconds
- Step 3: Adds ”→ Complete!” after 1 second
How to Use
Section titled “How to Use”- Start Chain: Run the chain with the default value
- Clear Log: Clear the log and progress
- Custom Input: Run the chain with a custom value
This demo visually shows that Timeline’s bind chain can achieve a sequence of asynchronous operations similar to Promise.then. You can see in real-time, through a terminal-style UI, how each step waits for the completion of the previous step before executing sequentially。