I have an object (foo) that exposes several methods as promises (using jQuery deferred). The way I did it ended up with this kind of code:
var foo = createNewFoo();
$.when(foo.method1(arg))
.then(foo.method2)
.then(foo.method3);
I wish to refactor the below code to be nicer and look like this:
var foo = createNewFoo()
.method1(arg)
.method2()
.method3();
But I'm not sure how to implement foo that it would be possible.
Yes sure, you just need to extend your Deferreds to have these methods:
function MyRpc { // if you can use ES2015 - this should be a `class`
this._deferred = new $.Deferred();
}
// teach it to be a promise
MyRpc.prototype.then = function(onFulfilled, onRejected) {
return this._deferred.then(onFulfilled, onRejected);
};
// teach it to be a deferred
MyRpc.protototype.resolve = function(arg) {
this._deferred.resolve(arg);
};
MyRpc.prototype.reject = function(arg) {
this._deferred.reject(arg);
};
// define your methods!
MyRpc.prototype.method1 = function(arg) {
var p = this._deferred.then(function(value) {
// logic of `method1` from foo.method1 here
});
var rpc = new MyRpc(); // our continuation;
p.then(function(v) { rpc.resolve(v) }, function(e) { rpc.reject(e); });
return rpc;
};
Of course, with a real promise library all this is a lot easier than with jQuery's minimal promises.
This would let you do:
var rpc = new MyRpc();
rpc.method1(1).method1(2).method1(3); // can also `.then` here
I'm not sure it's worth it, but it works.
You will need to return a custom object with the methods you need, and let it have a promise for the state instead of the state as properties directly. In every of your methods, you'd need to call then on the wrapped promise, and return another instance that wraps a new promise for the new state (method result).
function Foo(promise) {
// make every instance a thenable:
this.then = promise.then.bind(promise);
// alternatively store the promise itself as a property and always call this.promise.then
}
function createNewFoo() {
return new Foo($.when({/* initial state */}));
}
Foo.prototype.method1 = function method1(args) {
return new Foo(this.then(function(curstate) {
// method logic here
// should `return` a new state - or a promise for it
});
};
Foo.prototype.method2 = …;
This is similar to the approaches outlined by Benjamin Gruenbaum and Louy, but with a much simpler implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With