patternjavascriptMinor
Custom function extending jQuery.Deferred
Viewed 0 times
functioncustomjquerydeferredextending
Problem
I couldn't find an example on how to have a custom function inherit jQuery's functions while leaving the original jQuery function I'm inheriting from unchanged (I wanted my function to have a
This works, but I really suspect it isn't the right way to do it.
An example usage:
read but didn't want it to get added to $.Deferred)This works, but I really suspect it isn't the right way to do it.
var DeferredFileEntry = function(){
var def = $.Deferred();
var promise = def.promise;
def.read = function(textFnCallback){ // <--this is the method I'm adding
return $.Deferred(function(newDefer){
var newDefer = $.Deferred();
def.done(function(fileEntry){
fileEntry.getText()
.done(function(text){
textFnCallback(text);
newDefer.resolve(fileEntry);
});
});
}).promise();
};
def.promise = function(){
//expose the custom method to the returned promise
promise.read = def.read;
return promise();
};
return def;
};An example usage:
var getFileEntry = function(){
var def = DeferredFileEntry();
libraryCall() // that promises to resolve with a FileEntry object
.done(function(fileEntry){
def.resolve(fileEntry);
});
return def.promise();
}
getFileEntry()
.read(function(text){
console.log("reading content:" + text);
})
.read(function(text){
//chained,
//doesn't run until the previous one has resolved
console.log("reading content again: "+text);
});Solution
Tips:
1)
Returning
Example:
2)
The passed arguments from
Therefore the callbacks stored from
Example:
Different results can be produced if a function or object is passed to
Example:
3)
The callbacks passed to
The queue is set like so,
Also notes that the callbacks are fired in order of First in First out.
Final Code:
This might work. Instead of extending the deferred object to include a read method, I opted to return an plain object.
Note: My code is assuming that
Code:
Usage:
1)
Returning
this from a function of an object instance allows for the method to become chainable.Example:
var File = function(){
this.readCallCount = 0;
return this;
};
File.prototype.readLine = function(){
this.readCallCount++;
console.log( "read line: " + this.readCallCount );
return this;
};
var fileA = new File();
fileA.readLine().readLine().readLine();
/*
output:
read line: 1
read line: 2
read line: 3
*/2)
The passed arguments from
deferred.resolve() are saved until deferred.resolve() is invoked again. Therefore the callbacks stored from
deferred.done() will be passed the same values from the last call from deferred.resolve().Example:
var arr = [];
function log(str){
return arr.push( str );
}
function fn1(time) {
return log( "fn1 called at " + time );
}
function fn2(time) {
return log( "fn2 called at " + time );
}
var dfd = $.Deferred();
dfd.done(fn1);
dfd.resolve( +(new Date()) );
setTimeout(function(){
dfd.done(fn2);
console.log( arr.join( ", " ) );
}, 2000);
/*
outputs after 2 seconds
fn1 called at 1348177948625, fn2 called at 1348177948625
*/Different results can be produced if a function or object is passed to
deferred.resolve().Example:
var arr = [];
function log(str){
return arr.push( str );
}
function fn1(getTimeFunc) {
return log( "fn1 called at " + getTimeFunc() );
}
function fn2( getTimeFunc ) {
return log( "fn2 called at " + getTimeFunc() );
}
var dfd = $.Deferred();
dfd.done(fn1);
dfd.resolve(function(){
return +(new Date())
});
setTimeout(function(){
dfd.done(fn2);
console.log( arr.join( ", " ) );
}, 2000);
/*
output after 2 seconds
fn1 called at 1348178107859, fn2 called at 1348178109860
*/3)
The callbacks passed to
deferred.done() are saved in a callback queue called $.Callbacks(). The queue is set like so,
jQuery.Callbacks("once memory"). This means that all the callbacks stored in the queue will only fired once and that every callback receieves the same arguments.Also notes that the callbacks are fired in order of First in First out.
Final Code:
This might work. Instead of extending the deferred object to include a read method, I opted to return an plain object.
Note: My code is assuming that
libraryCall() and fileEntry.getText() return a deferred.promise() or deferred object.Code:
var FileEntryObj = function(){
this.libraryCallObj = libraryCall();
};
FileEntryObj.prototype.read = function(fn){
this.libraryCallObj.done( function( fileEntry ){
return fileEntry.getText().done( fn );
});
return this;
};
var getFileEntry = function(){
return new FileEntryObj();
};Usage:
getFileEntry().read(function (text) {
console.log("reading content:" + text);
}).read(function (text) {
console.log("reading content again: " + text);
});Code Snippets
var File = function(){
this.readCallCount = 0;
return this;
};
File.prototype.readLine = function(){
this.readCallCount++;
console.log( "read line: " + this.readCallCount );
return this;
};
var fileA = new File();
fileA.readLine().readLine().readLine();
/*
output:
read line: 1
read line: 2
read line: 3
*/var arr = [];
function log(str){
return arr.push( str );
}
function fn1(time) {
return log( "fn1 called at " + time );
}
function fn2(time) {
return log( "fn2 called at " + time );
}
var dfd = $.Deferred();
dfd.done(fn1);
dfd.resolve( +(new Date()) );
setTimeout(function(){
dfd.done(fn2);
console.log( arr.join( ", " ) );
}, 2000);
/*
outputs after 2 seconds
fn1 called at 1348177948625, fn2 called at 1348177948625
*/var arr = [];
function log(str){
return arr.push( str );
}
function fn1(getTimeFunc) {
return log( "fn1 called at " + getTimeFunc() );
}
function fn2( getTimeFunc ) {
return log( "fn2 called at " + getTimeFunc() );
}
var dfd = $.Deferred();
dfd.done(fn1);
dfd.resolve(function(){
return +(new Date())
});
setTimeout(function(){
dfd.done(fn2);
console.log( arr.join( ", " ) );
}, 2000);
/*
output after 2 seconds
fn1 called at 1348178107859, fn2 called at 1348178109860
*/var FileEntryObj = function(){
this.libraryCallObj = libraryCall();
};
FileEntryObj.prototype.read = function(fn){
this.libraryCallObj.done( function( fileEntry ){
return fileEntry.getText().done( fn );
});
return this;
};
var getFileEntry = function(){
return new FileEntryObj();
};getFileEntry().read(function (text) {
console.log("reading content:" + text);
}).read(function (text) {
console.log("reading content again: " + text);
});Context
StackExchange Code Review Q#15743, answer score: 5
Revisions (0)
No revisions yet.