Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chaining promises without using 'then'

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.

like image 550
Nissim Hania Avatar asked May 17 '26 05:05

Nissim Hania


2 Answers

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.

like image 105
Benjamin Gruenbaum Avatar answered May 18 '26 18:05

Benjamin Gruenbaum


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.

like image 39
Bergi Avatar answered May 18 '26 17:05

Bergi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!