Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork0
A powerful and efficient coroutine/microthreading library for TypeScript.
License
sator-imaging/ts-fibers
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
🇺🇸 English ❘ 🇯🇵 日本語版 ❘ 🇨🇳 简体中文版
ts-fibers is a powerful and efficientcoroutine/microthreading library for TypeScript, designed to help you manage asynchronous operations and long-running tasks without causing CPU usage spikes or excessive memory allocation. It leverages TypeScript'sGenerator andAsyncGenerator features to provide fine-grained control over task execution, making your applications more responsive and resource-friendly.
- Concurrency Control: Easily manage the level of concurrent task execution.
- Efficient Operations: Optimized performance using native
GeneratorandAsyncGenerator. - Background Task Execution: (Experimental) Run Fiber tasks in the background, freeing up the main thread.
- Ordered Results: Get results back in the order they complete, with options to track original task context.
- Robust Error Handling: Define custom error handling strategies for your Fiber tasks.
- Promise Integration: Seamlessly integrate with standard JavaScript Promises for task lifecycle management.
- Module Support:
ESM,CJSandUMDare supported.
ts-fibers provides two primary factory methods for creating Fibers instances:Fibers.forEach for array enumeration andFibers.for for sequential operations.
UseFibers.forEach to process elements of an array concurrently.
import{Fibers}from'ts-fibers';// Example: Download from provided urls concurrently, with a concurrency level of 5constfibers=Fibers.forEach(5,// Maximum concurrent tasksurls,// Array to iterate overasync(url)=>{returnawaitdownloadAsync(url);});// iterate through completed tasks using `for await...of`forawait(constdownloadedDataoffibers){console.log(`Download completed:${downloadedData.title}`);}
UseFibers.for when you need to iterate over a range of numbers, similar to afor loop.
import{Fibers}from'ts-fibers';// Example: Download 310 files concurrently, with a concurrency level of 5constfibers=Fibers.for(5,// Maximum concurrent tasks0,310,1,// Start index, End index (exclusive) and Stepasync(index)=>{returnawaitdownloadAsync(`https://...${index}.bin`);});// iterate through completed tasks using `for await...of`forawait(constdownloadedDataoffibers){console.log(`Download completed:${downloadedData.title}`);}
Fibers returns finished tasks in order as they complete. However, sometimes the original source index or array element is crucial for further processing. You can easily pack this source information into your Fibers task's result.
import{Fibers}from'ts-fibers';constfibers=Fibers.for(concurrency,startIndex,endIndex,step,async(index)=>{constvalue=awaitfooAsync(index);// 💡 Pack index with result to allow tracking jobreturn{ index, value};});forawait(constresultoffibers){if(result.index===1)continue;console.log(`${result.index}:${result.value}`);}// The iteration order may not be sequential by index, but the job index is always tracked// 3: delta// 0: alpha// 2: charlie
Warning
This feature is experimental and subject to change. Use with caution in production environments.
Fibers background tasks are executed on the main thread. This allows you to "fire and forget" tasks, managing their lifecycle and errors asynchronously.
import{Fibers}from'ts-fibers';constfibers=Fibers.for(concurrency,startIndex,endIndex,step,async(index)=>{if(someCondition(index))thrownewError(`Error for task${index}`);returnawaitbackgroundTask(index);});// Set a state for the fibers to track the job in the backgroundfibers.state='background job #1';// Register an error handlerfibers.setErrorHandler((e,fibersInstance,reason)=>{if(fibersInstance.state)console.error(`Error in${fibersInstance.state}:${e.message}`);// Decide how to handle the error: 'skip', 'stop', or 'default' (re-throw)// Here, we skip the task if it's from 'background job #1', otherwise re-throwreturnfibersInstance.state==='background job #1' ?'skip' :'default';});// Register promise callbacks for the overall fibers lifecyclefibers.promise.then(()=>console.log('Background fibers completed successfully!')).catch(err=>console.error('Background fibers encountered an unhandled error:',err.message)).finally(()=>console.log('Background fibers process finished.'));// Ready to start the fibers in the background (fire and forget)fibers.start();// You can stop the fibers after a certain time or condition// Note: stop() won't suspend running (queued) tasks; it just stops queueing new taskssetTimeout(()=>{console.log('Stopping background fibers after 3 seconds...');fibers.stop();},3000);
Fibers instances provide aPromise<void> handle via the.promise property, allowing you to use standardthen,catch, andfinally callbacks for the overall Fibers lifecycle.
Note
The resulting promise handle is for theFibers instance itself,NOT for the individual promises of the running jobs within the Fibers.
import{Fibers}from'ts-fibers';constfibers=Fibers.for(...);// Register callbacks for the fibers' lifecyclefibers.promise.then(...).catch(...).finally(...);// Start the fibersconststartPromise=fibers.start();// startPromise will be resolved on stop() or when fibers is completed// ie. `await fibers.start()` is same to `await fibers.promise`// When stopped, of course, promise callbacks are NOT invokedconststopPromise=fibers.stop();// stopPromise will be resolved when currently-queued fibers tasks are completed// If you don't await, tasks may still be running in the backgroundawaitstopPromise;// Restart fibers and wait for completion without 'for await...of'fibers.start();awaitfibers.promise;// Note: There is a fail-safe property '.promiseStart' that will invoke start()// automatically to avoid an indefinitely loop caused by awaiting a stopped fibers// promise callbacks are invoked!!
Oncestart() is called on a Fibers instance, attempting to usefor await...of on the same instance will throw aFiberError until the fibers is completed or explicitly stopped. Conversely, callingstart() within afor await...of loop will throw aFiberError too.
import{Fibers,FiberError}from'ts-fibers';constfibers=Fibers.forEach(...);// Scenario 1: Calling start() then using for await...offibers.start();forawait(constresultoffibers){}// Throws FiberError// Scenario 2: Calling start() inside for await...offorawait(constresultoffibers){fibers.start();// Throws FiberError}
A simple helper method to wait for a specified number of milliseconds, similar tosetTimeout but withPromise andAbortController integration.
import{Fibers}from'ts-fibers';console.log('Waiting for 1 second...');awaitFibers.delay(1000);console.log('1 second passed!');// Work with AbortController to cancel the delayconstac=newAbortController();console.log('Starting a 5-second timer, but will abort after 1 second...');consttimer=Fibers.delay(5000,ac);timer.finally(()=>console.log('finished or aborted'));setTimeout(()=>{ac.abort();// Stop timer immediately!console.log('Timer aborted!');},1000);
We welcome contributions!
About
A powerful and efficient coroutine/microthreading library for TypeScript.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.