Skip to content

Instantly share code, notes, and snippets.

@uolcano
Last active August 25, 2016 15:36
Show Gist options
  • Save uolcano/a9172d74e8588a58aa4dec84f27ea92b to your computer and use it in GitHub Desktop.
Save uolcano/a9172d74e8588a58aa4dec84f27ea92b to your computer and use it in GitHub Desktop.
Some performance optimization
function isArray (arg) {
return Object.prototype.toString.call(arg).slice(8, -1) === 'Array';
}
/**
* [chunk Array chunk iteration]
* @param { array } arr [array to iterate]
* @param {function} fn [function to process array]
* @param {integer } intv [iteration interval milliseconds]
* @param {function} success [function for async invocation when iteration complete]
* @param { object } ctx [context to invoke the function]
*
* usage:
* chunk([1, 2, 3], function(e, i, a){
* console.log(i, e);
* });
*/
function chunk(arr, fn, intv, success, ctx) {
var copy, idx;
if(!isArray(arr)) {
console.log('Error: chunk - parameter 1 must be an array.');
return;
}
if(!arr.length) {
console.log('Warning: chunk - parameter 1 must be an array with at least one element.');
return;
}
if(typeof fn !== 'function') {
console.log('Error: chunk - parameter 2 must be a function.');
return;
}
if(intv != null && (typeof intv !== 'number' || intv !== ~~intv)) {
console.log('Error: chunk - parameter 3 must be an integer.');
return;
}
if(success != null && typeof success !== 'function') {
console.log('Error: chunk - parameter 4 must be a function for async invocation.');
return;
}
if(ctx != null && typeof ctx !== 'object') {
console.log('Error: chunk - parameter 5 must be an object.');
return;
}
copy = arr.slice();
idx = 0;
intv = intv || 100;
intv = intv > 0 ? ~~intv : 0; // get the positve integer interval milliseconds
setTimeout(function f() {
var itm = copy.shift();
fn.call(ctx, itm, idx++, arr);
if(copy.length > 0) {
setTimeout(f, intv);
} else if(typeof success === 'function') {
// used for async invocation
success();
}
}, 0);
}
/**
* [throttle Function throttle]
* @param {function} fn [invoked function to throttle]
* @param {integer } intv [interval milliseconds]
* @param { array } params [parameters passed into the invoked function]
* @param { object } ctx [context to invoke the function]
*
* usage:
* document.addEventListener('click', function(e){
* throttle(doSomething, 1000, e.target.nodeType);
* throttle(doSomething, 1000, e.target.childNodes);
* throttle(doSomething, 1000, [null]);
* });
* function doSomething(data){
* console.log(data);
* }
*/
function throttle (fn, intv, params, ctx) {
if(typeof fn !== 'function') {
console.log('Error: throttle - parameter 1 must be a function.');
return;
}
if(intv != null && typeof intv !== 'number') {
console.log('Error: throttle - parameter 2 must be a number.');
return;
}
if(ctx != null && typeof ctx !== 'object') {
console.log('Error: throttle - parameter 4 must be an object.');
return;
}
clearTimeout(fn.tId);
intv = intv || 100;
if(params == null) params = [];
if(!isArray(params)) {
if(typeof params.length === 'number' && typeof params[0] !== 'undefined') {
params = Array.prototype.slice.call(params);
} else {
params = [params];
}
}
fn.tId = setTimeout(function () {
fn.apply(ctx, params);
}, intv);
}
/**
* [advDuff Iterator for large data]
* @param { object } arrLike [object has length property to access elements]
* @param {Function} fn [function to process arrLike]
*
* usage:
* advDuf([1,2,3], (e, i) => {console.log(i, e);});
* advDuff(document.querySelectorAll('li'), (e, i) => {console.log(i, e);});
*/
function advDuff (arrLike, fn) {
var len, trav, left, i;
if(typeof arrLike !== 'object' || typeof arrLike.length !== 'number') {
console.log('Error: advDuff - parameter 1 must be an array or array-like object');
return;
}
if(!arrLike.length) return;
if(typeof fn !== 'function') {
console.log('Error: advDuff - parameter 2 must be a function to process the parameter 1.');
return;
}
len = arrLike.length;
trav = ~~(len / 8); // get the integer turns of iteration
left = len % 8; // get the remainder of turns
i = 0;
if(left> 0) {
do{
fn(arrLike[i++], i, arrLike);
} while (--left>0);
}
if(!trav) return;
do{
fn(arrLike[i++], i, arrLike);
fn(arrLike[i++], i, arrLike);
fn(arrLike[i++], i, arrLike);
fn(arrLike[i++], i, arrLike);
fn(arrLike[i++], i, arrLike);
fn(arrLike[i++], i, arrLike);
fn(arrLike[i++], i, arrLike);
fn(arrLike[i++], i, arrLike);
} while (--trav > 0);
}
/**
* [trampoline To optimize the recursion]
* @param {function} fn [function to recurse]
* @return { any } [final result of recursive function]
*
* usage:
* function fibonacci (n, ac1 = 1, ac2 = 1) {
* return n <= 1 ? ac2 : () => fibonacci(n - 1, ac2, ac1 + ac2);
* }
* trampoline(fibonacci(1000, 1, 1));
*/
function trampoline (fn) {
while (fn && fn instanceof Function) {
fn = fn();
}
return fn;
}
/**
* [tail Tail-call optimizing function]
* @param {function} fn [function to recurse]
* @return { any } [final result of recursive function]
*
* usage:
* var fibonacci = tail((n, ac1 = 1, ac2 = 1) => {
* return n <= 1 ? ac2 : fibonacci(n - 1, ac2, ac1 + ac2);
* });
* fibonacci(1000, 1, 1);
*/
function tail (fn) {
var value,
active = false,
stack = [];
return function () {
stack.push(arguments);
if(!active) {
active = true;
while (stack.length) {
value = fn.apply(this, stack.shift());
}
active = false;
return value;
}
};
}
function isArray (arg) {
return Object.prototype.toString.call(arg).slice(8, -1) === 'Array';
}
/**
* Recursion: factorial
*/
/* non tail-call */
function factorial (n) {
return n === 1 ? 1 : n * factorial(n - 1);
}
/* tail-recursion */
function tailFactorial (total, n) {
return n === 1 ? total : tailFactorial(n * total, n - 1);
}
/* advanced encapsulation */
// 1: inner invocation
function factorial (n) {
return tailFactorial(1, n);
}
// 2: function currying
function curry (fn, args) {
if(!isArray(args)) args = [args];
return function (params) {
if(!isArray(args)) params = [params];
return fn.apply(this, args.concat(params));
};
}
var factorial = curry(tailFactorial, 1);
// 3: ES6 function parameter default value
function factorial (n, total = 1) {
if(n === 1) return 1;
return n * factorial(n - 1, n * total);
}
/**
* Recursion: fibonacci
*/
/* non tail-call */
function fibonacci (n) {
return n <= 1 ? 1 : fibonacci(n - 1) + fibonacci(n - 2);
}
/* tail-recursion */
function fibonacci (n, ac1 = 1, ac2 = 1) {
// 'use strict';
// (ac1 = ac1 || 1), (ac2 = ac2 || 1);
return n <= 1 ? ac2 : fibonacci(n - 1, ac2, ac1 + ac2);
}
/**
* Iterative recursion
*/
function factorial (n) {
var fact = 1;
while (n > 1) {
fact *= n--;
}
return fact;
}
function fibonacci (n) {
var ac1, ac2, tmp,
i = ac2 = ac1 = 1;
while(n > i++) {
(tmp = ac2),
(ac2 = ac1 + ac2),
(ac1 = tmp);
}
return ac2;
}
/**
* implementation of tail-recursion
*/
/* trampoline */
function trampoline (fn) {
while (fn && fn instanceof Function) {
fn = fn();
}
return fn;
}
function factorial (total, n) {
return n === 1 ? total : () => factorial(n * total, n - 1);
}
function fibonacci (n, ac1 = 1, ac2 = 1) {
return n <= 1 ? ac2 : () => fibonacci(n - 1, ac2, ac1 + ac2);
}
/* tail-call optimizing function */
function tail (fn) {
var value,
active = false,
stack = [];
return function () {
stack.push(arguments);
if(!active) {
active = true;
while (stack.length) {
value = fn.apply(this, stack.shift());
}
active = false;
return value;
}
};
}
var factorial = tail((total, n) => {
return n === 1 ? total : factorial(n * total, n - 1);
});
var fibonacci = tail((n, ac1 = 1, ac2 = 1) => {
return n <= 1 ? ac2 : fibonacci(n - 1, ac2, ac1 + ac2);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment