Taskq
Async module loader with declerative dependency management in HTML and compatibility with ES6 import/export
Install / Use
/learn @IbrahimTanyalcin/TaskqREADME
taskq
<a href="https://www.patreon.com/ibrahimTanyalcin" title="Patreon donate"><img src="https://img.shields.io/badge/patreon-donate-yellow.svg" alt="Patreon donate" /></a>
<a href="https://www.codacy.com/app/IbrahimTanyalcin/taskq?utm_source=github.com&utm_medium=referral&utm_content=IbrahimTanyalcin/taskq&utm_campaign=Badge_Grade" title="Codacy"><img src="https://api.codacy.com/project/badge/Grade/06f045df886848f09519df15388c8bf6" alt="Codacy Badge" /></a>
<a href="https://www.npmjs.com/package/@ibowankenobi/taskq" title="Npm"><img src="https://badge.fury.io/js/%40ibowankenobi%2Ftaskq.svg" alt="Npm Badge" /></a>
<a href="https://zenodo.org/badge/latestdoi/108156384"><img src="https://zenodo.org/badge/108156384.svg" alt="DOI"></a>
Async Modules Supporting ES5 & ES6 with Control Flow
⇩ First, your 1 min cheatsheet ⇩

<img src="https://upload.wikimedia.org/wikipedia/commons/6/6a/Detail_der_Rechenmaschine_von_Johann_Helfrich_M%C3%BCller.jpg" width="100%"></img>
Navigation
If you want you can jump straight into the examples.
Advantages ⏎
- <span style="font-size:200%;">0</span> dependencies
- No polyfill required
- No transpiling required.
- No config file etc.
- About 6kB when minimized
- Will work on ie9+.
- Will play nice with other technologies/patterns you use in your page
- Non-render blocking
- You can pause/resume the main thread
- Aware of document state (hidden, minimized etc.)
- Fine grained control on execution of all imported scripts.
- Uses Promises combined with requestAnimationFrame(rAF). Falls back to rAF on older browsers (ie etc).
- Supports nested/single dynamic imports. Your main thread will wait until a module finishes dynamically importing other modules.
- Supports then , catch phrases for dynamic imports.
- You can do things that you cannot do with ES6 directly:
taskq.load("./scriptDynamic1.js") .then(function(res){ res.init; setTimeout(function(){ console.log("setTimeout executed"); console.log("finally resolving"); res(true); },10000); console.log("dynamic script 1 'then' executed"); }) /*Next then will not execute until the above is resolved*/ .then(function(res){ console.log("dynamic script 1 'then-2' executed"); }); /*Meanwhile the entire downstream thread will wait for these tasks to finish*/ - Uses async script tags
- Does not dictate anything about your app structure. Whether you want use separate async script tags, or bundle them.
- No modifying required to your existing scripts other than wrapping them around iief (immediately invoked function expression) and pushing them to the taskq object.
API ⏎
There are some terms used throught out the documentation:
Terms
- iief: immediately invoked function expression
- main thread : this refers to the list of functions pushed to the taskq object before calling taskq.perform method. This is called automatically on 'onload' event. Dynamically loaded scripts have their separete queue (immediateTasks) that is handled implicitly.
- dynamic import/dynamic load : this is to refer whenever you call taskq.load method to start loading scripts somehere within main thread (or outside later if you want). Everything you load is async but their execution can be controlled by you.
- taskq: this is the main taskq global object. Although you can change its name using the script attribute, its default is assumed here.
- module pattern: Although taskq only requires you to push the functions to be executed, to avoid leaking to global, a general module pattern is as follows:
/*outer iief*/
!function(){
function someFunctionYouWantToExecute (someArguments) {
/*some stuff like taskq.export, taskq.load*/
}
taskq.push(someFunctionYouWantToExecute);
}()
Methods
taskq.version()
Returns the version string.
taskq.push(function)
Pushes the function to the main thread or the immediate thread (for dynamic imports) implicitly and return taskq it self, so you can do:
//Define functions
function f1(){...};
f1._taskqId = "f1";
function f2(){...};
f2._taskqId = "f2";
f2._taskqWaitFor = ["f1"];
function f3(){...};
f3._taskqId = "f3";
f3._taskqWaitFor = ["f2"];
//Push to queue
taskq.push(f1).push(f2).push(f3);
Pushed functions do not execute automatically, you will have to call taskq.perform() to start shifting and executing it. In your main HTML, perform is automatically called for you on 'onload' event.
If you push a variable that is not a function, it will be skipped and you will get a console message: "not a function ref".
taskq.export(variable,aliasString)
Exports any type of variable with the given alias. These exported variables are available to the pushed functions. Suppose a previouslyPushedFunction in the main thread called taskq.export({value:4},"someObject"):
/*outer iief*/
!function(){
function someFunctionYouWantToExecute (someObject) {
/*someObject is available here*/
}
someFunctionYouWantToExecute.taskqWaitFor = ["previouslyPushedFunction"];
taskq.push(someFunctionYouWantToExecute);
}()
Arguments order does not matter.
Exported variables live until taskq.perform finishes executing all the functions in the main thread. If there are no more pointers somewhere else in your code, they can be garbage collected. Later you can repopulate the exports by calling taskq.export again. Next time you call perform, it will again clear and so on.
taskq.load("./someScript.js")
Will pause the main thread, and start loading the given script. Its iief will be immediately executed and pushed functions will be added to the immediate queue to be executed. Returns a thennable object which you can attach then or catch clauses.
Other dynamic loads and the main thread will wait for this load to complete its iief, pushed functions and then/catch clauses.
thennable.then(function(resolver){...})
Attaches the thennable a function to be executed, and return the thennable itself. Attached thens are executed in order. Functions within thens are passed an optional resolver argument. If you do not call resolver.init; , the next then clause will execute as soon as this then clause is executed. If you call resolver.init; , somewhere else within the current then clause you should call resolver(true) or resolver(false) to proceed to the next then.
When using resolver, the entire main thread and the rest of the then clauses will wait for it to resolve.
thennable.catch(function(){...})
Attaches a catch clause to the thennable shall any of the thens resolve with a falsey value. Attaching multiple catch clauses overrides the previous one.
resolver.init
Tells the current then clause to block rest of the thens and the main thread and wait until it is resolved.
resolver(variable)
Converts the variable to "boolean" and resolves with that value. Returns always true unless you try to resolve more than once within the same then clause. You can only resolve once, resolving more than once does not have any effect -> only the first resolve value is recorded.
resolve.value
Gives the boolean value the resolver resolved with. Cannot be set.
taskq.pause;
Pauses the entire taskq main thread, thens etc. If any functions were called at the time pause was called such as pushed functions or setTimeout, they are executed and the rest is halted. When paused, taskq is still running but does not proceed.
taskq.paused;
Returns true of false whether taskq is paused or not. Cannot be set manually.
taskq.resume;
Resumes the taskq.
taskq.running;
Returns true or false based on taskq running state. It will return false once the taskq.perform() method finished the main thread. If you start another main thread, it return true until perform completes again.
taskq.perform()
Starts performing the pushed functions in the main thread. This is automatically called for you on the 'onload' event.
Later if you start another main thread by pushing functions to taskq, you should manually call this method in the end.
Perform will automatically clear all the exports once it is complete.
taskq.flush("main"|"script")
This is automatically called by the taskq.perform method in the end. You normally should not call this method manually. If you pass "main" as argument, then all the pushed functions to the main thread and the exported variables will be cleared. If you pass "script", only the immediate tasks (pushed functions within dynamic imports) are cleared.
taskq.minPause = Number
You can use this setter to set the minimum time in milliseconds between the execution of pushed functions in the main thread. You can also configure this by adding an "data-min-pause" attribute to the script tag of taskq.
Reading ⏎
I advise you to take a look at below Medium posts:
- Queued Async (pseudo-) modules with ES5
- Pausing/resuming browser & app logic using Taskq.js
- Get that google PSI score higher
What does it do? ⏎
This project has evolved to the degree that is now a full blown module system that can be used instead of ES6 import/export or other module proposals. Perhaps it can be better illustrated in answer I have written in Hashnode:
[Modules in JavaScript confusion](
Related Skills
node-connect
349.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
349.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
349.0kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
