diff --git a/README.md b/README.md
index 9ddc9dd..ec87ead 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
# taskq
+[![Build Status](https://travis-ci.org/IbrahimTanyalcin/taskq.svg?branch=master)](https://travis-ci.org/IbrahimTanyalcin/taskq)
@@ -28,8 +29,9 @@ If you want you can jump straight into the [**examples**](#examples-).
- No polyfill required
- No transpiling required.
- No config file etc.
-- About 5kB when minimized
+- 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.)
@@ -61,7 +63,133 @@ If you want you can jump straight into the [**examples**](#examples-).
## API [⏎](#api)
-push,export,then,catch,load,pause,resume,paused,running,perform,flush,minPause,res.init,res(true/false)
+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 [⏎](#reading)
@@ -194,7 +322,7 @@ Eventually all pushed functions are executed at the 'load' event (by the interna
If you want me to extend the capability to dynamically important scripts after the 'load' event, let me know.
-Check out the **[MINIMAL EXAMPLE](./example)** and also **[THIS](https://medium.com/@ibowankenobi/queued-async-pseudo-modules-with-es5-812f99fed209)** medium post. Also you can support me at my **[PATREON](https://www.patreon.com/ibrahimTanyalcin)** page.
+Check out the **[MINIMAL EXAMPLE](#example---2)** and also **[THIS](https://medium.com/@ibowankenobi/queued-async-pseudo-modules-with-es5-812f99fed209)** medium post. Also you can support me at my **[PATREON](https://www.patreon.com/ibrahimTanyalcin)** page.
## Examples [⏎](#examples)
@@ -214,6 +342,8 @@ The expected execution order of the scripts are:
The execution order is controlled by attaching *_taskqId* (any javascript variable type) and *_taskqWaitFor* (array of '*taskqId*'s) properties to the *pushed* functions inside iiefs.
+Note that **the first 3 lines of console messages** in the below examples can vary as the iiefs can execute in any order due to the *async* attribute of the script tags.
+
Although you should carefully examine all the scripts in each example, some important script for each example is highlighted, which is usually **'script1'**.
### Example - 1
@@ -222,6 +352,8 @@ This example has been explained in detail [**HERE**](https://medium.com/@ibowank
### Example - 2
+> Summary: The main thread will wait for completion of any dynamically imported (loaded) scripts and their then clauses, and will resume afterwards.
+
> script 1:
```
@@ -258,6 +390,8 @@ As expected iiefs execute first. And then based on the *_taskqWaitFor* propertie
### Example - 3
+> Summary: Everytime a function is pushed to the main thread, the main thread will wait for all dynamic loads within this function.
+
> script 0 (similarly scripts 1 and 2):
```
@@ -298,6 +432,8 @@ Here all the main scripts import a single dynamic module. And each time, the mai
### Example - 4
+> Summary: The main thread will also wait for nested dynamic loads within a pushed function.
+
> script 1:
```
@@ -362,6 +498,8 @@ After all the thens are executed, "scriptDynamic1_2.js" gets loaded and its then
### Example - 5
+> Summary: Within a dynamically loaded module/script, first the iief is executed, then its pushed function is executed, then all the then clauses are executed in order.
+
> script 1:
```
@@ -448,6 +586,8 @@ So within the flow of script 1:
### Example - 6
+> Summary: Dynamicall loaded scripts/modules and main initial script tags share the same pattern: a function wrapped inside iief where it is ultimately pushed to the taskq by the iief. However, dynamically loaded modules do not push the functions to the main thread, but to a separate 'immediate' thread. This is done implicitly.
+
> scriptDynamic1.js:
```
@@ -494,7 +634,7 @@ dynamic script 2 'then' executed
> explanation:
-The difference between this example and [example 5]() is dynamically imported functions also push another function to the queue.
+The difference between this example and [example 5](#example---5) is dynamically imported functions also push another function to the queue.
When dynamically loading scripts, note that the pushed functions execute before the then clauses as shown in the console messages.
@@ -506,6 +646,8 @@ Dynamically loaded scripts do not push functions into the queue of the main thre
### Example - 7
+> Summary: Any pushed function in the main thread or dynamically loaded script can export a variable. These variables are accessible to all the functions. The life cycle of these exported variables are till the end of the main thread, where they are ultimately flushed automatically.
+
> scriptDynamic2.js:
```
@@ -566,10 +708,12 @@ In this case, script 2 dynamically loads another script that reads these variabl
### Example - 8
-This is identical to [example 1]() with the addition of dynamically loaded scripts. It demonstrates how nested loads (dynamically loaded script loading another one) are handled.
+This is identical to [example 1](#example---1) with the addition of dynamically loaded scripts. It demonstrates how nested loads (dynamically loaded script loading another one) are handled.
### Example - 9
+> Summary: The then clauses gets passed a resolver argument. Thens are executed immediately unless you call *res.init*. You can later resolve it within the then clause by *res(true|false)*. You cannot resolve it twice, to check the value, use *res.value*. Resolving with falsey value will result in the next then clauses to be skipped and execution of a catch clause, if any.
+
> script1.js:
```
@@ -645,6 +789,8 @@ In this particular case first then clause within 'script1.js' is executed. The n
### Example - 10
+> Summary: Then clauses will wait for each others *res* to resolve before they execute. This is also true for dynamically loaded scripts and their then clauses. The main thread will wait for all of these nested clauses to complete and resolve before continuing.
+
> script1.js:
```
@@ -712,12 +858,14 @@ dynamic script 2 'then' executed
> explanation:
-This is similar to [example 9](). The difference is that the first then clause dynamically imports another script 'scriptDynamic1_1.js' within the setTimeout before it resolves.
+This is similar to [example 9](#example---9). The difference is that the first then clause dynamically imports another script 'scriptDynamic1_1.js' within the setTimeout before it resolves.
The 3 first layer then clauses are executed in order, within the first then clause the loading of 'scriptDynamic1_1.js' is added to the script queue. Once the first layer 3 then clauses are executed, 'scriptDynamic1_1.js' executes. The (second layer) then clause of 'scriptDynamic1_1.js' resolves in about 5 seconds. After that, the main thread continues with script2.
### Example - 11
+> Summary: When a then clause resolves with a *falsey* value, its remaining then clauses are skipped and the **latest attached** catch clause is executed.
+
> script1.js:
```
@@ -797,7 +945,7 @@ dynamic script 2 'then' executed
> explanation:
-This is almost identical to [example 10]() with the addition of second then clause resolving with a *falsey* value. The same then clause also exports a boolean variable called 'status'.
+This is almost identical to [example 10](#example---10) with the addition of second then clause resolving with a *falsey* value. The same then clause also exports a boolean variable called 'status'.
Due resolving with false at second then clause, the rest of the then clauses do not execute. If any catch handler attached, it executes which in this case logged: "This is the catch function attached!".
@@ -807,6 +955,8 @@ This is almost identical to [example 10]() with the addition of second then clau
### Example - 12
+> Summary: Then clauses can only be resolved with a boolean value. To share return values or other variables between then clauses or other functions, use the *taskq.export* method. Exporting a variable with the same alias overwrites it.
+
> scriptDynamic0.js:
```
@@ -920,7 +1070,7 @@ dynamic script 2 'then' executed
> explanation:
-This is very similar to [example 11]() with an addition of passing then clause parameters about the previous pushed function.
+This is very similar to [example 11](#example---11) with an addition of passing then clause parameters about the previous pushed function.
In example 11, you might wonder is there any way for the then clause of "./scriptDynamic1_1.js" to react to what has been returned or done within the pushed function (open "./scriptDynamic1_1.js" and look for the function named "conditional", this was the pushed function).
diff --git a/example/minTest/minimal.html b/example/minTest/minimal.html
new file mode 100644
index 0000000..c7008ce
--- /dev/null
+++ b/example/minTest/minimal.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh the page with console open to see the console messages!
+ For more info see this
+
+ MEDIUM
+
+ post.
+
+
+
\ No newline at end of file
diff --git a/example/minTest/script0.js b/example/minTest/script0.js
new file mode 100644
index 0000000..2bfe9f1
--- /dev/null
+++ b/example/minTest/script0.js
@@ -0,0 +1,12 @@
+!function(){
+ function script0(){
+ console.log("script0 executed");
+ taskq.load("./scriptDynamic0.js")
+ .then(function(){
+ console.log("dynamic script 0 'then' executed");
+ });
+ }
+ script0._taskqId = "script0";
+ taskq.push(script0);
+ console.log("scrip0 iief executed");
+}()
\ No newline at end of file
diff --git a/example/minTest/script1.js b/example/minTest/script1.js
new file mode 100644
index 0000000..42040f0
--- /dev/null
+++ b/example/minTest/script1.js
@@ -0,0 +1,49 @@
+!function(){
+ function script1(retValue){
+ console.log("script1 executed");
+ taskq.load("./scriptDynamic1.js")
+ .then(function(res){
+ res.init;
+ setTimeout(function(){
+ console.log("setTimeout executed");
+ taskq.load("./scriptDynamic1_1.js")
+ .then(function(res){
+ res.init;
+ setTimeout(function(){
+ console.log("dynamic script 1_1 said: " + retValue.value);
+ console.log("dynamic script 1_1 'then' executed");
+ res(true);
+ },5000)
+ });
+ console.log("finally resolving");
+ res(true);
+ },10000);
+ console.log("dynamic script 1 'then' executed");
+ })
+ .then(function(res){
+ res.init;
+ setTimeout(function(){
+ res(false);
+ taskq.export(false,"status");
+ console.log("catch will be executed, rest of the thens will be skipped.");
+ },5000);
+ })
+ .then(function(res){
+ res.init;
+ setTimeout(function(){
+ console.log("dynamic script 1 'then-2' executed");
+ res(true);
+ },5000)
+ })
+ .then(function(){
+ console.log("dynamic script 1 'then-3' executed");
+ })
+ .catch(function(){
+ console.log("This is the catch function attached!");
+ });
+ }
+ script1._taskqId = "script1";
+ script1._taskqWaitFor = ["script0"];
+ taskq.push(script1);
+ console.log("scrip1 iief executed");
+}()
\ No newline at end of file
diff --git a/example/minTest/script2.js b/example/minTest/script2.js
new file mode 100644
index 0000000..27520c0
--- /dev/null
+++ b/example/minTest/script2.js
@@ -0,0 +1,13 @@
+!function(){
+ function script2(){
+ console.log("script2 executed");
+ taskq.load("./scriptDynamic2.js")
+ .then(function(){
+ console.log("dynamic script 2 'then' executed");
+ });
+ }
+ script2._taskqId = "script2";
+ script2._taskqWaitFor = ["script1"];
+ taskq.push(script2);
+ console.log("scrip2 iief executed");
+}()
\ No newline at end of file
diff --git a/example/minTest/scriptDynamic0.js b/example/minTest/scriptDynamic0.js
new file mode 100644
index 0000000..75afbe4
--- /dev/null
+++ b/example/minTest/scriptDynamic0.js
@@ -0,0 +1,5 @@
+!function(){
+ console.log("Dynamic-0 Script loaded");
+ console.log("Exporting retValue");
+ taskq.export({value:undefined},"retValue");
+}()
\ No newline at end of file
diff --git a/example/minTest/scriptDynamic1.js b/example/minTest/scriptDynamic1.js
new file mode 100644
index 0000000..74c2064
--- /dev/null
+++ b/example/minTest/scriptDynamic1.js
@@ -0,0 +1,3 @@
+!function(){
+ console.log("Dynamic-1 Script loaded");
+}()
\ No newline at end of file
diff --git a/example/minTest/scriptDynamic1_1.js b/example/minTest/scriptDynamic1_1.js
new file mode 100644
index 0000000..3d54002
--- /dev/null
+++ b/example/minTest/scriptDynamic1_1.js
@@ -0,0 +1,16 @@
+!function(){
+ function conditional(status,retValue){
+ if (status) {
+ console.log("I will execute!");
+ } else {
+ console.log("I will NOT execute!");
+ taskq.pause;
+ setTimeout(function(){
+ retValue.value = "I will NOT execute!";
+ taskq.resume;
+ },10000);
+ }
+ }
+ taskq.push(conditional);
+ console.log("Dynamic-1_1 Script loaded");
+}()
\ No newline at end of file
diff --git a/example/minTest/scriptDynamic2.js b/example/minTest/scriptDynamic2.js
new file mode 100644
index 0000000..e477ebe
--- /dev/null
+++ b/example/minTest/scriptDynamic2.js
@@ -0,0 +1,3 @@
+!function(){
+ console.log("Dynamic-2 Script loaded");
+}()
\ No newline at end of file
diff --git a/package.json b/package.json
index 3b42fe0..7c57224 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,8 @@
"example": "example"
},
"scripts": {
- "test": "node tests/test.js"
+ "test": "node tests/test.js",
+ "min": "./node_modules/.bin/uglifyjs taskq.js -c -m -o ./taskq.min.js"
},
"repository": {
"type": "git",
diff --git a/paper/paper.bib b/paper/paper.bib
new file mode 100644
index 0000000..46e3a18
--- /dev/null
+++ b/paper/paper.bib
@@ -0,0 +1,39 @@
+@article{Deogen2,
+ author = "Raimondi, D. and Tanyalcin, I. and Ferté, J. and Gazzo, A. and Orlando, G. and Lenaerts, T. and Rooman, M. and Vranken, W.",
+ Title = {DEOGEN2: prediction and interactive visualization of single amino acid variant deleteriousness in human proteins.},
+ publisher = "Nucleic acids research",
+ doi = {10.1093/nar/gkx390},
+ YEAR = 2017,
+}
+
+@article{Lexicon,
+ author = "Tanyalcin, I. and Al Assaf, C. and Ferté, J. and Ancien, F. and Khan, T. and Smits, G. and Rooman, M. and Vranken, W.",
+ Title = {Lexicon Visualization Library and JavaScript for Scientific Data Visualization},
+ publisher = "Computing in Science and Engineering",
+ doi = {10.1109/MCSE.2018.011111125},
+ YEAR = 2018,
+}
+
+@online{Npm,
+ author = {Npm},
+ title = {npmjs.com},
+ year = 2018,
+ url = {https://www.npmjs.com/},
+ urldate = {2018-02-19}
+}
+
+@online{GitHub,
+ author = {GitHub},
+ title = {GitHub.com},
+ year = 2018,
+ url = {https://github.com},
+ urldate = {2018-02-19}
+}
+
+@online{TC39,
+ author = {Ecma International},
+ title = {Ecma TC39},
+ year = 2018,
+ url = {https://github.com/tc39},
+ urldate = {2018-02-19}
+}
\ No newline at end of file
diff --git a/paper/paper.md b/paper/paper.md
new file mode 100644
index 0000000..8492981
--- /dev/null
+++ b/paper/paper.md
@@ -0,0 +1,42 @@
+---
+title: 'Async Modules Supporting ES5 & ES6 with Control Flow'
+tags:
+ - ES5
+ - ES6
+ - promise
+ - Promise
+ - async
+ - javascript
+ - task
+ - queue
+ - requestAnimationFrame
+ - d3
+ - js
+ - biojs
+ - bionode
+ - pause
+ - resume
+ - module
+ - Control Flow
+authors:
+ - name: Ibrahim Tanyalcin
+ orcid: 0000-0003-0327-5096
+ affiliation: 1
+affiliations:
+ - name: Vrije Universiteit Brussel
+ index: 1
+date: 19 February 2018
+bibliography: paper.bib
+---
+
+# Summary
+
+Javascript has evolved immensely the last 20 years with its usage spreading across multiple branches of science. This had led to more complex UI designs to meet user demands as in case of scientific data visualizations etc. The expansion of utility libraries has raised the need for a module system.
+
+Many module proposals/implementations are in use today, including the ES6 import/export syntax. Taskq differentiates by giving the user the control over the pace of execution of modules and other dynamically imported scripts while taking advantage of the async attribute.
+
+Taskq uses a combination of Promises with requestAnimationFrame (rAF) and falls back to rAF on older browsers including ie9. Since it does not dictate anything else about the app structure, it can be used in the browser with other technologies. It's about 6kB (as of version 2.1.4) minimized and does not need any transpiling to use in older browsers.
+
+Taskq concept can make it easier to implement complex workflows in the browsers which frequently required by scientific software.
+
+# References
\ No newline at end of file
diff --git a/taskq.js b/taskq.js
index b354dea..ee377fc 100644
--- a/taskq.js
+++ b/taskq.js
@@ -23,6 +23,8 @@
factory(root,root.document);
}
}(this,function(window,document){
+ //version
+ var version = "2.1.4";
//a salt for getters/setters
var salt = Math.random();
//current script
@@ -96,9 +98,14 @@
}
}
);
+ /*taskq resonates between 3 stages. If taskq.onload is called,
+ scriptLoading is true and scriptComplete is false, once script is loaded,
+ scriptLoading is false and scriptLoaded is true, once all pushed
+ functions execute and thens are consumed, scriptComplete is true*/
this.scriptLoading = false;
this.scriptLoaded = false;
this.scriptComplete = true;
+ /*clear main thread or the immediate thread*/
this.flush = function(origin){
if (origin === "main") {
tasks = [];
@@ -108,11 +115,14 @@
}
return this;
};
+ /*export variables with alias*/
this.export = function(f,name){
name = name || "default";
exports[name] = f;
return this;
};
+ /*if onload is encountered, push the immediateTasks,
+ otherwise push to main thread*/
this.push = function(f){
if(this.scriptLoading || this.scriptLoaded) {
//console.log("pushing this to immediate queue");
@@ -122,6 +132,7 @@
}
return this;
};
+ /*perform pushed functions*/
this.perform = function(){
this.execute(
this.sortTasks(tasks),
@@ -144,7 +155,11 @@
return this.promise.promise = new this.__promise;
}
};
+ /*set the minimum amount of time to pass between execution of
+ functions in the main thread*/
this.minPause = minPause;
+ /*taskq.load returns a thennable object,
+ for more refer to readme.md*/
this.thenable = function (that){
var queue = [],
_this = this,
@@ -197,9 +212,7 @@
this.then = function(f){
this.counter++;
queue.push(function(){
- //console.log("Queue executes??");
that.promise().then(function(){
- //console.log("Promise executes??");
f(_this.resolver);
if(!resolverIsInitiated) {
_this.counter--;
@@ -209,21 +222,26 @@
});
return this;
};
+ /*Starts executing the pushed functions within the
+ immediate tasks. Upon completion 'status.complete' will be set to
+ true and impender can start executing then clauses*/
this.execute = function(){
- //console.log("execute???");
that.execute (
that.sortTasks(immediateTasks),
exports,
{
origin:"script",
- status:/*this.status*/_this.status,
- flush:/*false*/true
+ status:_this.status,
+ flush:true
}
);
return this;
};
+ /*When a thennable is created, its impender is immediately active,
+ once status is complete, it starts executing the then clauses. When
+ all then clauses are finished, the next dynamic load, if any is
+ processed*/
this.impender = function(){
- //console.log("running!!");
if (!that.running) {
that.running = {hash:salt, value: true};
}
@@ -242,7 +260,6 @@
_catch();
}
if (scriptQueue.length) {
- //console.log("Do I keep shifting???");
scriptQueue.shift()();
}
return;
@@ -263,11 +280,13 @@
_this.next = false;
queue.shift()();
}
- //console.log(_this.next);
window.requestAnimationFrame(_this.impender);
};
this.impender();
};
+ /*If another load is encountered before current dynamic load
+ and its then clauses are processed, it is pushed to the
+ scriptQueue*/
this.queuePacker = function(src,container){
var thens = [],
that = this;
@@ -283,6 +302,11 @@
};
}),
prt = taskq.constructor.prototype;
+ prt.version = function(){
+ return version;
+ };
+ /*This internally called method is either passed the tasks array or
+ the immediateTasks array. Sorts the passed array and returns a shallow copy*/
prt.sortTasks = function(tasks){
//About max 2^16 tasks
var base = Math.max.apply(null,tasks.map(function(d,i){return (d._taskqWaitFor || []).length;})) + 1,
@@ -327,6 +351,7 @@
return d[0];
});
};
+ /*requestAnimationFrame (rAF) is used instead of Promise wrapper in older browsers (ie9+)*/
prt.__promise = function(){
this.then = function(f) {
window.requestAnimationFrame(f);
@@ -335,8 +360,6 @@
};
//execute the pushed & sorted functions one by one
prt.execute = function(sorted,exports,options){
- //console.log("execute MAIN???");
- //console.log(options.origin);
if (!this.running) {
this.running = {hash:salt, value: true};
}
@@ -409,6 +432,7 @@
};
window.requestAnimationFrame(tick);
};
+ /*Load scripts asynchronously and keep DOM clean*/
prt.load = function(src,container){
if(!this.scriptComplete) {
return this.queuePacker(src,container);
@@ -422,13 +446,11 @@
this.scriptComplete = false;
script.async = true;
script.onload = function(){
- //console.log("I fire too???");
that.scriptLoading = false;
that.scriptLoaded = true;
thenable.execute();
};
script.onerror = function(){
- //console.log("I fire???");
thenable.errored = true;
};
script.src = src;
diff --git a/taskq.min.js b/taskq.min.js
new file mode 100644
index 0000000..286487b
--- /dev/null
+++ b/taskq.min.js
@@ -0,0 +1 @@
+!function(t,e){if("object"!=typeof t.window&&"object"!=typeof t.document){var n=function(){},i={};t.window={requestAnimationFrame:n,addEventListener:n,document:{getElementById:n,querySelector:n,querySelectorAll:n,elementFromPoint:n,head:i,body:i}}}"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e(t.window,t.window.document):e(t,t.document)}(this,function(t,e){var n=Math.random(),i=e.querySelector("script[src*='taskq.js']"),r=i&&i.getAttribute("global-name")||"taskq",o=i&&+i.getAttribute("data-min-pause")||0,s=t[r]=new function(){var e=[],i={},r=[],s=[],u=Math.random(),a=!1,c=!1;Object.defineProperties(this,{paused:{configurable:!1,enumerable:!1,get:function(){return a},set:function(t){return"object"!=typeof t||t.hash!==u?(console.log("You cannot set this manually"),!1):"boolean"==typeof t.value&&(a=t.value,!0)}},pause:{configurable:!1,enumerable:!1,get:function(){var t=!a;return this.paused={hash:u,value:!0},t}},resume:{configurable:!1,enumerable:!1,get:function(){var t=a;return this.paused={hash:u,value:!1},t}},running:{configurable:!1,enumerable:!1,get:function(){return c},set:function(t){return"object"!=typeof t||t.hash!==n?(console.log("You cannot set this manually"),!1):"boolean"==typeof t.value&&(c=t.value,!0)}}}),this.scriptLoading=!1,this.scriptLoaded=!1,this.scriptComplete=!0,this.flush=function(t){return"main"===t?(e=[],i={}):"script"===t&&(r=[]),this},this.export=function(t,e){return i[e=e||"default"]=t,this},this.push=function(t){return this.scriptLoading||this.scriptLoaded?r.push(t):e.push(t),this},this.perform=function(){return this.execute(this.sortTasks(e),i,{origin:"main"}),this},this.promise=function(){return this.promise.promise?this.promise.promise:t.Promise&&Promise.constructor===Function?this.promise.promise=Promise.resolve():this.promise.promise=new this.__promise},this.minPause=o,this.thenable=function(e){var o=[],u=this,c=void 0,h=!1,f=!1,p=function(){};this.errored=!1,this.rejected=!1,this.catch=function(t){return"function"==typeof t&&(p=t),this},this.target=e,this.status={complete:!1},this.counter=0,this.next=void 0,this.resolver=Object.defineProperties(function(t){return!h&&((c=!!t)?(u.counter--,u.next=!0):u.rejected=!0,h=!0)},{init:{configurable:!1,enumerable:!1,get:function(){return f=!0}},value:{configurable:!1,enumerable:!1,get:function(){return c}}}),this.then=function(t){return this.counter++,o.push(function(){e.promise().then(function(){t(u.resolver),f||(u.counter--,u.next=!0)})}),this},this.execute=function(){return e.execute(e.sortTasks(r),i,{origin:"script",status:u.status,flush:!0}),this},this.impender=function(){if(e.running||(e.running={hash:n,value:!0}),!a&&(u.errored||u.rejected||!u.counter&&u.status.complete))return e.running={hash:n,value:!1},e.scriptLoaded=!1,e.scriptComplete=!0,u.rejected&&p(),void(s.length&&s.shift()());a||!u.status.complete||void 0!==u.next&&!u.next||(f=!1,h=!1,c=void 0,u.next=!1,o.shift()()),t.requestAnimationFrame(u.impender)},this.impender()},this.queuePacker=function(t,e){var n=[],i=this;return s.push(function(){n.forEach(function(t,e){this.then(t)},i.load(t,e))}),new function(){this.then=function(t){return n.push(t),this}}}},u=s.constructor.prototype;return u.version=function(){return"2.1.4"},u.sortTasks=function(t){var e=Math.max.apply(null,t.map(function(t,e){return(t._taskqWaitFor||[]).length}))+1,n=["start","init","begin","loadstart","loadStart"],i=["end","defer","finish","loadend","loadEnd"];return t.map(function(t,e){return[t,t._taskqId]}).sort(function(t,e){var r=t[1],o=e[1];return~n.indexOf(r)?~n.indexOf(o)?0:-1:~i.indexOf(r)?~i.indexOf(o)?0:1:0}).map(function(t,e){return[t[0],t[0]._taskqWaitFor]}).sort(function(t,e){var n=t[1],i=e[1];return n?i?0:1:i?-1:0}).map(function(t,e){return[t[0],t[0]._taskqId,t[1]]}).sort(function(t,n){var i=t[1],r=n[1],o=t[2]||[],s=n[2]||[];return o.some(function(t,e){return t===r})*e+o.length-s.some(function(t,e){return t===i})*e-s.length}).map(function(t,e){return t[0]})},u.__promise=function(){this.then=function(e){return t.requestAnimationFrame(e),this}},u.execute=function(e,i,r){if(this.running||(this.running={hash:n,value:!0}),!e.length)return(void 0===r.flush||r.flush)&&this.flush(r.origin),r.status&&(r.status.complete=!0),void(this.running={hash:n,value:!1});var o=this,s=this.promise(),u=Date.now();s=s.then(function(n){t.requestAnimationFrame(function(){var n=e.shift(),s=0;if("function"==typeof n){var a=/function\s*\w*\s*\(((?:\s*\w+\s*\,?\s*)*)\)\s*\{/.exec(n.toString());n.apply(i[n._taskqScope]||t,a?a[1].replace(/\s+/g,"").split(",").map(function(t,e){return i[t]}):void 0)}else console.log("not a function ref");!o.paused&&(s=Date.now()-u)>=o.minPause&&("main"===r.origin&&o.scriptComplete||"script"===r.origin)?o.execute(e,i,r):o.wait(o.minPause-s,e,i,r)})})},u.wait=function(e,n,i,r){var o=this,s=0,u=function(a){s=s||a,!o.paused&&e+s-a<=0&&("main"===r.origin&&o.scriptComplete||"script"===r.origin)?o.execute(n,i,r):t.requestAnimationFrame(u)};t.requestAnimationFrame(u)},u.load=function(t,n){if(!this.scriptComplete)return this.queuePacker(t,n);n=n||e.head;var i=this,r=n.querySelector("script[src*='"+t.replace(/\?.*$/gi,"")+"']"),o=e.createElement("script"),s=new this.thenable(i);return this.scriptLoading=!0,this.scriptComplete=!1,o.async=!0,o.onload=function(){i.scriptLoading=!1,i.scriptLoaded=!0,s.execute()},o.onerror=function(){s.errored=!0},o.src=t,r?n.replaceChild(o,r):n.appendChild(o),s},t.addEventListener("load",function(){s.perform()},!1),s});
\ No newline at end of file