36

With Q I can define a new promise with:

var queue = q();

But with Bluebird if I do:

var queue = new Promise();

I get:

TypeError: the promise constructor requires a resolver function

How can I get the same result that I had with Q?

This is a snippet of my code:

var queue    = q()
    promises = [];
queue = queue.then(function () {
    return Main.gitControl.gitAdd(fileObj.filename, updateIndex);
});
// Here more promises are added to queue in the same way used above...
promises.push(queue);
return Promise.all(promises).then(function () {
   // ...
});
Fez Vrasta
  • 14,110
  • 21
  • 98
  • 160
  • 1
    FYI the `q` function is same as `Promise.cast` while `Promise` function is same as `q.promise`. So the equivalent of `q()` is `Promise.cast()` – Esailija Mar 29 '14 at 07:33

4 Answers4

37

Florian provided a good answer For the sake of your original question, there are several ways to start a chain with Bluebird.

One of the simplest is calling Promise.resolve() on nothing:

var queue = Promise.resolve(); //resolve a promise with nothing or cast a value

or

Promise.try(function(...){
    return ...//chain here
});

So you can do:

var queue    = Promise.resolve()
    promises = [];
queue = queue.then(function () {
    return Main.gitControl.gitAdd(fileObj.filename, updateIndex);
});

// Here more promises are added to queue in the same way used above...
promises.push(queue);
return Promise.all(promises).then(function () {
   // ...
});

Although, personally I'd do something like:

//arr is your array of fileObj and updateIndex

Promise.map(arr,function(f){ return Main.gitControl.gitAdd(f.filename,f.updateIndex).
    then (function(result){
        //results here
    });
Matthias M
  • 12,906
  • 17
  • 87
  • 116
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • If you want each gitAdd to wait for the next, you should use `Promise.reduce` instead of `Promise.map`. – Benjamin Gruenbaum Mar 27 '14 at 14:06
  • 3
    Why is `Promise.resolve()` better than `Promise.cast()`? – Florian Margaine May 12 '14 at 12:16
  • 3
    @FlorianMargaine good quesiton, Promsie.resolve is in the ES6 spec, when the API was created Promise.cast and Promise.resolve were both in the ES6 spec and Bluebird, I assume that `.cast` is going to be dropped in Bluebird 2.0. – Benjamin Gruenbaum May 12 '14 at 12:19
  • 3
    Both `Bluebird.defer()` and `Bluebird.cast()` are deprecated in 2.x versions, and to start a "clean" promise chain, it's better to use `Bluebird.resolve()` – pocesar Jul 04 '14 at 23:02
  • @pocesar that is correct, I'll remove the `.cast` as we deprecated it in 2.0 (or even 1.X iirc), where am I missing the `.defer` here? – Benjamin Gruenbaum Aug 27 '14 at 10:18
  • @BenjaminGruenbaum nowhere, just making note that both are deprecated :) – pocesar Aug 28 '14 at 19:54
23
var resolver = Promise.defer();
setTimeout(function() {
    resolver.resolve(something); // Resolve the value
}, 5000);
return resolver.promise;

This line is quite often used in the documentation.

Be aware that this is usually an anti-pattern to use that. But if you know what you're doing, Promise.defer() is a way to get the resolver that is similar Q's way.

It is, however, discouraged to use this method. Bluebird has even deprecated it.

Instead, you should use this way:

return new Promise(function(resolve, reject) {
    // Your code
});

See the relevant documentation bits: Promise.defer() and new Promise().


After the update of your question, here is your issue: you're reusing the same promise to resolve several values. A promise can only be resolved once. It means you have to use Promise.defer() as many times as you have promises.

That said, after seeing more of your code, it seems you're really using anti-patterns. One advantage of using promises is error handling. For your case, you'd just need the following code:

var gitControl = Promise.promisifyAll(Main.gitControl);
var promises = [];
promises.push(gitControl.gitAddAsync(fileObj.filename, updateIndex));
return promises;

This should be enough to handle your use case. It is a lot clearer, and it also has the advantage of really handling the errors correctly.

Florian Margaine
  • 58,730
  • 15
  • 91
  • 116
  • Thanks, I'll put a "FIXME" to replace the current method with the reccomended one. About the Q's way... Should I use `var resolver = Promise.defer(),queue = new Promise(resolver);`? It throws the same error. – Fez Vrasta Mar 27 '14 at 10:38
  • @FezVrasta see the [progress](https://github.com/petkaantonov/bluebird/blob/master/API.md#progressdynamic-value---undefined) example to see the usage of `Promise.defer()`. – Florian Margaine Mar 27 '14 at 10:40
  • I've updated my question adding a snippet of my code, I can't implement your suggested method there, I get the same error... May you help me? – Fez Vrasta Mar 27 '14 at 10:47
  • @FezVrasta you're only adding one promise to your `promises` array in your example. Is that only for the sake of the example? – Florian Margaine Mar 27 '14 at 10:48
  • yes in the real code there are conditions to add more promises – Fez Vrasta Mar 27 '14 at 10:49
  • Thanks, will try to apply it (https://github.com/zaggino/brackets-git/issues/127) – Fez Vrasta Mar 27 '14 at 11:02
  • 4
    @FlorianMargaine +1 Can you explain why `new Promise(function(...` is preferred over the use of `Promise.defer()` ? Just because it's "awkward" and "error prone" ? – Denys Séguret Mar 27 '14 at 14:15
  • I've had to switch `pending` for `defer` and `resolve` for `fulfill` in version 2.9.30 – NickL Jun 26 '15 at 08:57
  • what is the use case for deferred? – SuperUberDuper Oct 19 '15 at 14:48
  • Can you please remove the first half of the answer, it no longer works at all and has moved past being deprecated. – 1mike12 Dec 15 '16 at 16:08
  • @SuperUberDuper, my specific example was I was querying the database for it's information schema, which lists out the names of my columns, then I cache the value and return that instead when another request comes in later. However, if I suddenly got 500 hits to that one async function and there was no previous entry in the cache, it would queue up 500 redundant queries. So now, I make 1 real query, and push 499 resolves, and when that 1 query returns, resolve the other 499 wiht the same data – 1mike12 Dec 15 '16 at 16:11
0

I came across this as I had a method which fetches a resource on the internet and returns the content, but I want it to handle connection timeouts and retrying up to X times with delays between.

As Bluebird.defer is deprecated, I used this which does this trick:

const Promise = require('bluebird');

var fetch = function (options, promise) {
    var resolve, reject;
    if (promise) {
        resolve = promise.resolve;
        reject = promise.reject;
        promise = promise.promise;
    } else {
        promise = new Promise(function () {
            resolve = arguments[0];
            reject = arguments[1];
        });
    }
    var retry = {promise: promise, resolve: resolve, reject: reject};

    // Your logic here that you want to retry
    if (typeof options.x === 'undefined') {
        reject(new Error('X not defined'));
    } else if (options.x < 3) {
        options.x++;
        options.retryAttempt = (options.retryAttempt || 0) + 1;
        console.log(`Retrying in 1 second attempt ${options.retryAttempt}...`);
        setTimeout(() => {
            fetch(options, retry)
        }, 1000);
    } else {
        resolve(options.x);
    }

    return promise;
}

fetch({x:0})
    .then(res => {
        console.log(res);
    })
    .catch(err => {
        throw err;
    });
Kus
  • 2,529
  • 27
  • 27
0

I find a pattern like this useful for any kind of integration testing.

const responseResolver;

const response = new Promise(resolve => {
    responseResolver = resolve;
}).then(data => {
    console.log("data: ", data);
    return data;
});

// mock some method that returns a promise (e.g. waits for a response)
service.getIceCreams = () => response;

// do some assertions while the response is pending

responseResolver("cookie dough"); // will trigger .then: "data: cookie dough"

// do some assertions now that the response is completed
Sam Berry
  • 7,394
  • 6
  • 40
  • 58