Reputation: 35194
I would like to get a similar functionality to this:
function foo(before, after){
before();
setTimeout(function(){
after();
},100)
}
foo(function(){
console.log('before');
}, function(){
console.log('after');
});
When returning an object instead of using callbacks (psuedo code):
var foo = function() {
before();
setTimeout(function(){
after();
},100)
return {
before: before,
after: after
}
};
foo().before(function(){
console.log('before');
});
foo().after(function(){
console.log('after');
});
Or perhaps even
foo().before(function(){
console.log('before');
}).after(function(){
console.log('after');
});
Is this possible?
Upvotes: 2
Views: 106
Reputation: 1923
Phrogz' answer is good but FWIW you can also do this without prototypes:
function foo() {
ret = function () { return ret.call(); };
ret.call = function () {
this._before();
setTimeout(this._after,100);
};
ret.before = function (x) { this._before = x; return this; };
ret.after = function (x) { this._after = x; return this; };
return ret;
};
test = foo().before(function(){
console.log('before');
}).after(function(){
console.log('after');
});
Calling:
test();
does what you would expect.
Upvotes: 1
Reputation: 128317
It's almost possible.
The problem with your proposed usage example, though, is that it involves foo()
being called before before
or after
callbacks are specified. Meanwhile, in your example implementation, these callbacks are executed within foo
. So that isn't achievable: you can't retroactively change what happened in a method after that method has already run.
If what you really want is for the callbacks supplied via foo
to be executed nearly right away—i.e, if pure synchronous execution isn't mandatory—you can get what you're after with a simple setTimeout
call:
function foo() {
var callbacks = {
before: function() {},
after: function() {}
};
setTimeout(function() {
callbacks.before();
setTimeout(callbacks.after, 100);
}, 0);
return {
before: function(callback) {
callbacks.before = callback;
return this;
},
after: function(callback) {
callbacks.after = callback;
}
};
}
Here, foo()
will return an object that exposes methods to modify the callbacks
object closed over within the method body of foo
. These methods will then be used on the next tick of the event loop, after foo()
has executed.
I've created an example at JSBin if you're interested in seeing this code in action.
Upvotes: 2
Reputation: 700302
Yes, your function can return an object with before
and after
methods that keep track of which callbacks has been set, and when both are set it can call them:
function foo() {
var beforeFunc = null, afterFunc = null;
function activate() {
beforeFunc();
window.setTimeout(afterFunc, 100);
}
var obj = {
before: function(f) {
beforeFunc = f;
if (afterFunc != null) activate();
return obj;
},
after: function(f) {
afterFunc = f;
if (beforeFunc != null) activate();
return obj;
}
};
return obj;
}
// As both callbacks need to be set, the order is not important
foo().after(function(){
console.log('After');
}).before(function(){
console.log('Before');
});
Demo: http://jsfiddle.net/4HypB/
Upvotes: 4
Reputation: 37763
Here's another variation:
var createFooBuilder = function () {
var before = function() {};
var after = function() {};
var func = function () {
before();
setTimeout(function () {
after();
}, 100)
};
func.before = function(value) {
before = value;
return func;
}
func.after = function(value) {
after = value;
return func;
}
return func;
};
var foo = createFooBuilder();
foo.before(function () {
console.log('before');
}).after(function () {
console.log('after');
});
foo();
I'd certainly recommend trying to make jQuery Deferreds work for you, then you can have lists of after functions.
Upvotes: 1
Reputation: 303215
function foo(){};
foo.prototype.before = function(f){ this._before = f };
foo.prototype.after = function(f){ this._after = f };
foo.prototype.go = function(){
this._before();
setTimeout(this._after,100);
}
var f = new foo;
f.before(function(){ … });
f.after(function(){ … });
f.go();
But then again, you might as well make this simpler:
function foo(){};
foo.prototype.go = function(){
this.before();
setTimeout(this.after,100);
}
var f = new foo;
f.before = function(){ … };
f.after = function(){ … };
f.go();
Upvotes: 1