📜 ⬆️ ⬇️

Convenient callback

Tired of writing Kolbek hands every time. I wrote a simple scriptin that remembers a function (functions) with an array of arguments and a context in an object with a fire method that does not depend on this, so that you can hook a colback not only in the “clean” code, but also on the click or timer. The set of executable functions and arguments / context for each of them is arbitrary.

From gingerbread only an opportunity to crush bugs, limit the number of kolbek starts and the convenience of baking other gingerbreads to your taste.

Scriptina itself

function _callback(fn, args, ctx, decorators) {
// -
// fn - ():
// , {fn: function, args: [], ctx: {}},
// ,
// args -
// ctx - (this)
// decorators - ,
//
var ret = new _callback.Def(fn, args, ctx);
if (decorators) {
var d = _callback.decorators;
for ( var key in decorators) {
if (key in d) ret = new d[key](ret, fn, args, ctx, decorators[key]);
}
}
return ret;
}
_callback.Def = function (fn, args, ctx) {
var dublicate = this ; // myClb.fire dom-,
//
var arrayOrNull = function (ar) { return ar && ar.constructor == Array ? ar : null ; };

setFn(fn);

this .updateFn = updateFn;
//this.__defineSetter__("fn", setFn); // ie
//this.__defineGetter__("fn", function() { return fn; });

function fireByFn(myArgs, myFn, myCtx) {
// -
(myFn || fn).apply(myCtx || ctx || null , arrayOrNull(myArgs) || arrayOrNull(args) || []);
return dublicate;
}
function fireByArray(myArgs, myFn, myCtx) {
// ,
for ( var i=0, ar=myFn||fn, c=myCtx||ctx, a=arrayOrNull(myArgs) || arrayOrNull(args), l=ar.length; i<l; i++) getFireFn(ar[i])(a, ar[i], c);
return dublicate;
}
function fireByJSON(myArgs, myJson, myCtx) {
// JSON
var json = myJson || fn;
getFireFn(json.fn)(arrayOrNull(json.args) || arrayOrNull(myArgs), json.fn, json.ctx || myCtx);
return dublicate;
}

function getFireFn(fn) {
//
var type = dublicate._getTypeofFireFn(fn), fireFn;
switch (type) {
case "json" : return fireByJSON; break ;
case "array" : return fireByArray; break ;
case "function" : return fireByFn; break ;
}
return fireFn;
}

function setFn(val) {
// fire
dublicate.fire = getFireFn(fn = val);
}
function updateFn(transformFn) {
setFn(transformFn(fn));
return dublicate;
}
};
_callback.Def.prototype._err = function () { this ._err.withoutFn(); };
_callback.Def.prototype._err.withoutFn = function () {
throw "_callback: wrong fn argument" ;
};
_callback.Def.prototype._getTypeofFireFn = function (fn) {
// : , ,
if (!fn) this ._err.withoutFn();
if ( typeof fn == "function" ) return "function" ;
if (fn.constructor == Array) {
for ( var i=fn.length; i--;) this ._getTypeofFireFn(fn[i]);
return "array" ;
} else {
// {}
this ._getTypeofFireFn(fn.fn);
return "json" ;
}
this ._err.withoutFn();
};
_callback.decorators = {};
_callback.decorators._copy = function (component, orig, instance) {
for ( var key in component) orig[key] = instance[key] = component[key];
//instance.__defineSetter__("fn", function(val) { component.fn = val; }); // ie
//instance.__defineGetter__("fn", function() { return component.fn; });
};
_callback.decorators.count = function (component, fn, args, ctx, misc) {
var orig = {};
_callback.decorators._copy(component, orig, this );
var fired = misc;

this .fire = fire;

function fire() {
if (!fired) return ;
fired--;
component.fire();
}
};
_callback.decorators.stopThrow = function (component, fn, args, ctx, misc) {
var orig = {};
_callback.decorators._copy(component, orig, this );
this .fire = fire;

function fire() {
try {
component.fire();
} catch (er) {}
}
};
_clb = _callback;


* This source code was highlighted with Source Code Highlighter .


Usage example

Prepare functions that will respond to .fire
var res = "" ;
addLine = function (str) {
res += str + "\n" ;
};

function f1(q, w, e) {
addLine( "f1: " + q + ", " + w + ", " + e + "; this.q = " + this .q);
}
function f2(q, w, e) {
addLine( "f2: " + q + ", " + w + ", " + e + "; this.q = " + this .q);
}
function f3(q, w, e) {
addLine( "f3: " + q + ", " + w + ", " + e + "; this.q = " + this .q);
}
function f4(q, w, e) {
addLine( "f4: " + q + ", " + w + ", " + e + "; this.q = " + this .q);
}
function f5() {
uNdEfInEd++;
addLine( "f5" );
}


* This source code was highlighted with Source Code Highlighter .

')
And, actually, an example of using
// :
q = _clb(
f1, // , ...
[1,2,3], // ... ...
{q:5} // ... (this.q==5)
);
q.fire(); //
// f1: 1, 2, 3; this.q = 5
q.fire([8]); //
// f1: 8, undefined, undefined; this.q = 5
q.fire( false , false , {q:11}); // , this
// f1: 1, 2, 3; this.q = 11
q.fire([]); //
// f1: undefined, undefined, undefined; this.q = 5
addLine( "----" ); //
//
q = _clb([f1, f2, f3], [1,2,3], {q:5}); // ,
q.fire();
// f1: 1, 2, 3; this.q = 5
// f2: 1, 2, 3; this.q = 5
// f3: 1, 2, 3; this.q = 5
q.fire([8]); // ""
// f1: 8, undefined, undefined; this.q = 5
// f2: 8, undefined, undefined; this.q = 5
// f3: 8, undefined, undefined; this.q = 5
addLine( "----" );

// JSON :
q = _clb(
[
f1, // f1: 1, 2, 3; this.q = 5
{fn: f2, args: [4, 5, 6]}, // f2: 4, 5, 6; this.q = 5
{
fn: [
f2, // f2: 7, 8, 9; this.q = 0
{fn: f2, args: [4, 5, 6]}, // f2: 4, 5, 6; this.q = 0
f3 // f3: 7, 8, 9; this.q = 0
],
args: [7, 8, 9], //
ctx: {q: 0} //
}
],
[1,2,3], //
{q:5} //
).fire();
addLine( "----" );

// :
q.updateFn( function (fn) {
// ,
fn.splice(1, 5);
fn.push(f1, f1);
return fn;
}).fire(); // : f1: 1, 2, 3; this.q = 5
addLine( "----" );

// ie, __defineSetter__ __defineGetter__ :
//q.fn = [f2, {fn: f2, args: [], ctx: {}}, {fn: f3, args: [7, 8, 9], ctx: {q: 0}}];
//q.fire();
//addLine("----");

// :
q = _clb(f5, false , false , {stopThrow: true }).fire(); //

// - :
q = _clb(f1, [1,2,3], {q:5}, {count: 1});
q.fire(); // f1: 1, 2, 3; this.q = 5
// 1 0
q.fire(); //

alert(res);


* This source code was highlighted with Source Code Highlighter .
I think I'm not the only one so smart and I would like to know other options.

Source: https://habr.com/ru/post/99636/


All Articles