• enQue.js

  • ¶

    enQue class Author leathan License MIT

    'use strict'
  • ¶

    Constructor Creates a new enQue object with the specified functions. que = new enQue([fn1, fn2, fn3]) You can also create an empty object via new enQue()

    function enQue(init) {
      this.que = [];
      if(init) this.add(init);
  • ¶

    returns itself for use in chaining

      return this;
    }
  • ¶

    Compact Removes undefined and null values. This method should never ever be called directly, and it will probably become private in the future.. but who knows. que.compact()

    enQue.prototype.compact = function() {
      var i = 0;
      const res = [];
      for (let val of this.que) if(val) res[i++] = val;
      this.que = res;
  • ¶

    returns itself for use in chaining

      return this;
    }
  • ¶

    enQue.fill Fills an enQue object with fn‘s n times. que.fill((_,n)=>{console.log('works');n()}, 7) running that que will display ‘works’ 7 times.

    enQue.prototype.fill = function(fn, n) {
      for(let i = 0; i < n; i++) {
        this.que.push(fn);
      }
  • ¶

    returns itself for use in chaining

      return this;
    }
  • ¶

    enQue.add Adds fn to the enQue object. que.add((_,n,__,i)=>{console.log(i)}) or you can specify an array of functions que.add([fn1, fn1])

    enQue.prototype.add = function(fn) {
      if(fn.constructor.name === 'Array') {
        for(let i = 0, l = fn.length; i < l; i++) {
          this.que.push(fn[i]);
        }
      } else {
        this.que.push(fn);
      }
  • ¶

    returns itself for use in chaining

      return this;
    }
  • ¶

    enQue.clear Clears all functions from the que que.clear()

    enQue.prototype.clear = function() {
      this.que = [];
      return this;
  • ¶

    returns itself for use in chaining

    }
  • ¶

    enQue.remove Removes an item from the que. que.remove("(_,n,__,i)=>{console.log(i)}") que.remove(fn1, 2) removes 2 occurances of fn1 que.remove(7) removes the 8th function (0 indexed) to remove an array of function refs and/or strinfified functions. que.remove([fn1, "(_,n,__,i)=>{console.log(i)}", fn2]) que.remove([fn1, fn2, fn3], 2) will only remove fn1 and fn2.

    enQue.prototype.remove = function(item, amount) {
  • ¶

    Here we extract the items type.

      let type = item.constructor.name;
      if(type === 'Number') {
        return this.que.splice(item, 1);
      }
      else if(type === "Array") {
        amount = amount || Infinity;
        let removed = 0;
        for(let i=0, l=item.length; i<l; i++) {
          var check = item[i].constructor.name === 'Function' ? item[i] : item[i].toString();
          for(let j=0, l2=this.que.length; j<l2; j++) {
  • ¶

    Make sure we dont remove more than amount!

            if(removed === amount) break;
            if(this.que[j] === check) {
              delete this.que[j];
              removed++;
            }
          }
        }
  • ¶

    returns itself after compacting for use in chaining

        return this.compact();
      }
      else {
        let check = type === 'Function' ? item : item.toString();
        amount = amount || Infinity;
        let removed = 0;
        for(let i=0, l=this.que.length; i<l; i++) {
  • ¶

    Make sure we dont remove more than amount!

          if(removed === amount) break;
          if(check === check.constructor.name === 'Function' ? this.que[i] : this.que[i].toString()) {
            delete this.que[i]
            removed++;
          }
        }
  • ¶

    returns itself after compacting for use in chaining

        return this.compact();
      }
    }
  • ¶

    executeQue Executes the que, you should not need to call this function directly, for example if data doesnt exist you will not be able to consume/output properly. run makes sure data exists. On the offchance you need to bypass the promise system its avialable que.executeQue() but remember to pass in data and done if needed.

    enQue.prototype.executeQue = function(data, done) {
  • ¶

    preserve the original callback for potential que rebuilding.

      var orig = done;
  • ¶

    i is our iterator, quit and inject are used to check if we need to quit early and resolve the data, or inject Function.

      var i = 0, quit = false, inject = false, injectFn = false;
  • ¶

    The nest function allows us to itterate through the que while constantly nesting callbacks.

      this.nest((done, next) =>
        options => {
  • ¶

    Options can be any operation to perform while nesting callbacks. Currently options must be a specific JSON Object, or a Number, if its JSON then it needs a quit or inject property. Otherwise 0 terminates que, exposing the data immitiadtly. A negative Number sends the data to backwards in the que (to a new que techincally), Positive Numbers send the data forward, i is current callback index being nested.

          if(options === 0) return next = orig;
          if(options !== data && options === Object(options)) {
            if((!options.function && !options.inject) && !options.quit)
              throw new Error(`${options} is not supported, valid fomat could be +n, -n, 0, or, {quit:+n}, {inject:+n,function:Function}`)
            else if(options.quit) {
              quit = options.quit;
            }
            else if(options.inject) {
              inject = options.inject - 1;
              injectFn = options.function;
            }
          }
          else if(options !== data && options) {
  • ¶

    creates a temp que to hold our new que.

            let tmpQue = [];
  • ¶

    let j be the position we are skipping to. lets say next(-3) was passed, so options = -3. i is the current que spot - 1 that called next(-3). lets say i was 5, so we want to go back to 1. so j = 5 + -3 - (options < 0) = 1 so start at position 1, until the end.

            var j = i + options - (options < 0);
            if(!this.que[j-1]) throw `${options} out of bounds, no que position ${j} exists.`
            for(let l = this.que.length; j < l; j++) {
              tmpQue.push(this.que[j])
            }
  • ¶

    sets the que to the one we just built.

            this.que = tmpQue;
  • ¶

    Apends the original data exposure callback.

            this.que.push(orig)
            this.executeQue(data);
  • ¶

    Makes sure the current execution goes nowhere.

            done = ()=>{}
            next = ()=>{}
          }
  • ¶

    if quit is specified, checks if we need to quit and if so sets next to resolve data, otherwise de-increments the checker variable.

          if(quit !== false) {
            if(quit === 0) { next = orig; quit = false }
            else quit--;
          }
  • ¶

    if inject is specified, checks if we need to inject the Function if so waits it injects the function which is NOT part of the que and hence its execution is not synchronized, this will probably be fixed in the future. calls next, otherwise de-increments checker and calls next.

          if(inject !== false) {
            if(inject === 0) {
              next(data, done, i++, orig);
              injectFn(data);
              injectFn = inject = false;
            } else {
              inject--;
              next(data, done, i++, orig);
            }
          } else {
  • ¶

    no special object options were specified just proceeds.

            next(data, done, i++, orig)
          }
        }
  • ¶

    this sets our initial accumulator to the function done each successive call then creates another function callback nest where the old done becomes the callback of the new done the original done passed in here does nothing more then resolve the data. Which is passed in immidiatly since right after nesting the entire composition is executed.

      , done)(data);
    }
  • ¶

    enQue.run Creates a promise which resolves when the que ends. que.run(data) or for ques that dont consume data que.run() Since a promise is returns you should then call .then(data=>{}) and .catch(error=>{})

    enQue.prototype.run = function(data) {
  • ¶

    Allow ques that dont need to consume data.

      if(!data) data = {};
      return new Promise((resolve, reject) => {
        try {
          this.executeQue(data, () => resolve(data));
        } catch(error) {
          reject(error);
        }
  • ¶

    returns a promise which can be used for chaining

      })
    }
  • ¶

    enQue.nest This method should never be called directly unless you know what you are doing. que.nest()

    enQue.prototype.nest = function(callback, orig) {
      var que = this.que, pos = que.length - 1, nest;
  • ¶

    Set the initial done to resolve(data).

      nest = orig;
      for (; pos >= 0; pos--) {
  • ¶

    Now our original done is a callback. which keeps being nested till pos == 0.

        nest = callback(nest, que[pos]);
      }
  • ¶

    returns the fully nested object

      return nest;
    };
    
    module.exports = enQue;