Last active
August 25, 2016 15:36
-
-
Save uolcano/a9172d74e8588a58aa4dec84f27ea92b to your computer and use it in GitHub Desktop.
Some performance optimization
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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