1

I would like to know what do you think about this kind of extension for ES6 Promise (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise):

Promise.create = function() {
    var deferred;
    var promise = new Promise(function (resolve, reject) {
        deferred = {
            resolve: resolve,
            reject: reject
        };
    });

    promise.deferred = deferred;
    return promise;
}

Like that it avoid using the first callback to get cleaner code:

var requestsdeferred = Promise.create();
obj.myFunctionWithCallback(function(){
  obj.mySecondFunctionWithCallback(function(){
    requestsdeferred.resolve('all done!');
  });
});


requestsdeferred.then(function(result) {

});

instead of:

var p = new Promise(function(resolve, reject){
    obj.myFunctionWithCallback(function(){
      obj.mySecondFunctionWithCallback(function(){
        resolve('all done!');
      });
    });
});

p.then(function(){
});

Which need a callback.

What do you think ?

Dragouf
  • 4,676
  • 4
  • 48
  • 55
  • Just return the promise from both `ajax.get()` calls and you don't even need to construct your outer promise. No need to create a new promise when you already have promises being returned from your operations. You can just use those. – jfriend00 Sep 24 '15 at 01:51
  • Yes sorry. My example is wrong. My problem is not related to the way to wait for a promise but for a callback. I will edit it. – Dragouf Dec 21 '15 at 02:35
  • 1
    A deferred object like you are creating is simply not needed. See [When would someone need to create a deferred](http://stackoverflow.com/questions/32853105/when-would-someone-need-to-create-a-deferred/32857145#32857145) for a discussion on that topic. You also should not mix callbacks and promises because you lose throw safety and error propagation which are key benefits of promises. If you're using promises (which is recommended), then promisify your async operations and program your logic only with promises, not with a mix of callbacks and promises. – jfriend00 Dec 21 '15 at 03:26
  • Yes but when callback come from a library, how to do ? Moreover how to create a function which return a promise without the need of wraping it inside es6 promise callback ? – Dragouf Dec 21 '15 at 04:28
  • The idea is that you "promisify" all your async functions. This involves creating a wrapper around them so that rather than take the typical callback, they return a promise. You do this once in one place for the APIs you are using and then you can use those wrappers with a promise interface instead. It can seriously improve your programming productivity. – jfriend00 Dec 21 '15 at 04:47
  • There are also utility functions available to automate the promisify wrapper. I use the Bluebird promise library which has both a `Promise.promisify()` and `Promise.promisifyAll()` which will create promise wrappers for a single method or an entire API object. Or, if you don't want to use Bluebird, you can just create your own wrappers. Mixing callback APIs in the middle of promises negates many benefits of promises and is not recommended. – jfriend00 Dec 21 '15 at 04:48
  • yes I'm agree but my goal was not to mix callbacks with promise. I wanted to create wrapper class for libraries with callback method but in this wrapper class I wanted to avoid to wrap everything in es6 promise callback by using deferred pattern. About bluebird I dont want to add library dependency for such a small thing. Moreover bluebird rewrite his own promise. – Dragouf Dec 21 '15 at 05:15
  • You asked what we think. And, what I think is that none of these are a recommended practice. Instead, you should promisify (e.g. wrap individually to return a promise) both the `.myFunctionWithCallback()` and `.mySecondFunctionWithCallback()` methods and then program logic between them using only promises. So, regular callbacks are used only inside your promisify wrapper. – jfriend00 Dec 21 '15 at 09:23

2 Answers2

4

Neither is the correct/regular usage of a promise. The usual way to use a promise would be:

ajax.get('/get').then(function(){
  return ajax.get('/cart');
}).then(function(){
    alert('all done!');
});

Promises chain, you can return a promise from a then handler and it will cause the returned promise from the then to wait for its completion and assume its state.

Of course, unless the promises depend you can (and likely should) execute them concurrently:

Promise.all([ajax.get("/get"), ajax.get("/cart")]).then(function(results){
   // both done here, concurrently
});

Avoid the explicit construction anti-pattern, no need to create a deferred. The reason the API does not look the way you describe it is so that if you throw synchronously it will get converted to a rejection and you won't have to add both a .catch and a catch (e){ handler to your code which is error prone.

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • I know that we can chain promise and we can wait concurrently for them with all. The purpose of my code here is not to solve that. Maybe my example is not clear because I use get which return a promise. But the code here should be understand as: "what if I want to wait for callbacks without to wrap them inside ES6 promise callback". By creating a deferred interface I remove the global promise callback. – Dragouf Dec 21 '15 at 02:32
1

It's just an obfuscation of the ES6 standard, and I don't see much benefit to your addition. It's just a layer of abstraction that isn't really needed.

I'd suggest a different approach that plays nice with ES6 promises...

The following is correct, but irrelevant (see comments) : Any "thenable" can be turned into a standard Promise with Promise.resolve, so if your ajax is (for instance) created with jQuery's $.ajax, you might:

var prom1 = Promise.resolve(ajax.get('/get'));
var prom2 = Promise.resolve(ajax.get('/cart'));

We can create these together (so the requests run concurrently), then wait for all of the promises to complete with Promise.all:

Promise.all([req1, req2])
       .then(function(vals){
           //and get the results in the callback
           var getData = vals[0];
           var cartData = vals[1];
       });
spender
  • 117,338
  • 33
  • 229
  • 351
  • By passing the requests to `Promise.all`, `Promise.resolve` is already implicitly called on them. Also, the requests don't run in parallel they run concurrently. – Benjamin Gruenbaum Sep 24 '15 at 01:43
  • That I didn't know... Makes sense that it would though. – spender Sep 24 '15 at 01:49
  • My problem is not to wait for many concurrent promises. My problem is to transform javascript callback to promise without to wrap it inside ES6 promise callback. – Dragouf Dec 21 '15 at 02:34