UNPKG

@silver-zepp/sequence

Version:

Sequence - a JavaScript utility for managing complex chains of synchronous and asynchronous operations with timing control.

161 lines (143 loc) 5.93 kB
# Sequence `Sequence` is a `JavaScript` utility for managing complex chains of synchronous and asynchronous operations with timing control. ## Key Features - **Linear Readability**: Define sequences of operations in a clear, Arduino-like linear fashion. - **Timing Control**: Control over delays and execution timing. - **Async/Sync Mixing**: Combine synchronous and asynchronous tasks. - **Flow Control**: Pause, resume, and loop functionality for flexible execution. - **Parallel Execution**: Run tasks in parallel with timeout control. - **Error Handling**: Built-in error with `.catch()` and cleanup with `.finally()`; `try/catch` out of the box. - **State Management**: Track sequence state (idle, running, paused, completed, error). - **Composability**: Easily compose and reuse sequences. ## Use Cases - Animation sequencing (move a box from A to B, wait a second, move it to C) - Game development (cutscenes, scripted events) - API call orchestration (if this then that) - Any scenario requiring precise timing and sequencing of operations - Complex UI interactions ## Examples ```javascript // install -> npm i @silver-zepp/sequence import { Sequence } from '@silver-zepp/sequence'; // Example #0: Print Hello World after 1 second new Sequence() .delay(1000) // wait for 1000ms .log("Hello World") // print a message .start() // autostart this sequence // Example #1: A little bit more complex Arduino-like execution chain const seq = new Sequence() .log("1. Waiting 500 ms") .delay(500) .log("2. Waiting 1000 ms") .delay(1000) .log("3. Waiting 2000 ms") .delay(2000) .call(() => console.log("===> Custom function called")) .log("4. Starting parallel tasks") .parallel([ new Sequence().delay(1000).call(() => console.log("===> task [ 1 ] done")), new Sequence().delay(2000).call(() => console.log("===> task [ 2 ] done")) ], { wait_for_all: true, timeout: 3000 }) // wait for all parallel tasks to finish? this is done async .log("5. All parallel tasks completed or timed out") .log("6. All done") .loop() .start() // Example #2: async + context passing function asyncBlockA(resolve) { console.log('dummy async op...'); setTimeout(() => { console.log('dummy async op DONE after 2 seconds'); resolve({ ok: true, data: 'dummy data' }); }, 2000); } function blockB(data) { console.log(JSON.stringify(data)); } const seq = new Sequence() .log('Starting blocks A & B sequentially') .await(asyncBlockA, { timeout: 3000 }) // timeout of 3s (default 5s) .log('Block A executed waiting for 1s before going next') .delay(1000) .call((result) => blockB(result)) // using `result` from .await() method .log('All sequential tasks completed') .start(); // Example #3: Animate some things const seq = new Sequence() .log("Starting animation") .call(() => circle.add("fade-in")) // call arbitrary function .delay(500) .call(() => circle.add("move-up")) .delay(1000) .parallel([ // call multile functions at the same time in async manner new Sequence().call(() => circle.add("rotate")), new Sequence().call(() => updateText("Animation complete!")) ]) .log("Animation sequence finished") .start(); // Example #4: Operate with variables outside the sequence let check_count = 0; let is_destroyed = false; const checker = new Sequence() .call(() => { check_count++; is_destroyed = seq.isDestroyed(); if (is_destroyed) { console.log("Seq state:", JSON.stringify(seq)); checker.stop(); } else { console.log("Checker CHECKS:", check_count); } }) .delay(1000) .loop() .start() // Example #5: Basic parallelism new Sequence() .log("Starting parallel tasks") .parallel([ new Sequence().delay(2000).log("Task 1 done (2 sec)"), new Sequence().delay(1000).log("Task 2 done (1 sec)"), new Sequence().delay(4000).log("..."), // This task will timeout ], { mode: Sequence.PARALLEL_MODE_ALL, timeout: 3000 }) // note the mode selector .log("All parallel tasks completed") .start(); // Example #6: Timescale manipulation // aka make things slow down or speed up // 1.0 is the default speed; // at 0.5 the sequence will take twice the time // delay(1000) = 1s but delay(1000) at timescale 0.5 is equal to 2000 (!) Sequence.SetTimeScale(1.0); let count = 0; let delay_start_time = 0; const seq = new Sequence({ tick_interval: 50 }) .call(() => count++) .repeat(5) // this will loop the above code, making count = 5 .log("1. Count:", () => `${count} (index: ${seq.getCurrentTaskIndex()})`) .call(() => delay_start_time = Date.now()) .delay(1000) .log("2. After 1s delay") .log("Actual delay time:", () => `${Date.now() - delay_start_time}ms`) .log("TS:", Sequence.GetTimeScale, "DT:" , Sequence.GetDeltaTime) .log("3. Count:", () => `${count} (index: ${seq.getCurrentTaskIndex()})`) .repeat(5) // this will loop the whole code from above so the end count will be 5 * 5 = 25 .log("4. Execution finished") .call(()=> setTimeout(after, 300)) // execute external function that will check if the seq is destroyed .start(); function after(){ console.log(seq.isDestroyed()) } // Example #0 (again): Same old example but with a little bit more explanation new Sequence() .delay(1000) // wait for 1000ms .log("Hello World") // print a message .start() // autostart this sequence // Note: the sequence will autodestroy itself after execution // if you want to rerun it in the future, create the seq with autodestroy flag set to false const seq = new Sequence({ autodestroy: false }) .delay(1000) .log("Hello World") // this way you can start the sequence whenever you need and as many times as needed seq.start(); // ... seq.start(); ```