1

I've stepped into wonderful world of Promises a few days ago and I was just thinking I was enlightened. Promises look simple but they can be confusing.

Could you please tell me why the following test doesn't pass?

var Promise = require('bluebird');
var expect = require('chai').expect;
var request = Promise.promisifyAll(require('request'));

describe('Promise', function() {
    it('should work again', function() {

        var final_result;

        function first_promise() {
            return new Promise(function(resolve, reject) {
                resolve("http://www.google.com");
            })
        }

        function second_promise() {
            return new Promise(function(resolve, reject) {
                resolve("This is second promise!");
            })
        }

        function inner_async_request(url_from_first_promise) {
            return new Promise(function(resolve, reject) {
                return request.getAsync(url_from_first_promise).spread(function(response, content) {
                    final_result = content;
                    resolve(content);
                })
            })
        }

        return request.getAsync('http://127.0.0.1:3000/').spread(function(result, content) {
                //do something with content and then return first_promise
                console.log(content);
                return first_promise;
            })
            .then(function(url) {
                inner_async_request(url).then(function(result) {
                    console.log(result);
                    final_result = result;
                })
                return second_promise;
            })
            .then(function(result) {
                // result should be "This is second promise!"
                console.log(result);
                // final_result should be google's html
                expect(final_result).not.to.be.undefined;
            })
    });
});

Currently the error is: Unhandled rejection Error: options.uri is a required argument which should be received from first_promise, I guess?

By this test, actually, I want to understand how to use promises which depend on each other AND how to use promises as asynchronous functions inside promises -which should just work separately-.

Thank you

scaryguy
  • 7,720
  • 3
  • 36
  • 52
  • 1
    Are you calling `first_promise` in your actual code? You still need to call `first_promise` when returning. – Qantas 94 Heavy Apr 19 '15 at 10:13
  • 1
    Don't use the [Promise constructor antipattern](http://stackoverflow.com/q/23803743/1048572)! – Bergi Apr 19 '15 at 12:56
  • Thanks for the recommendation Bergi! I had seen that post of yours but couldn't get well, now I understand it better. But not the best, yet. Just better :) – scaryguy Apr 20 '15 at 22:40

1 Answers1

2

You need to call the functions to return promises, like

 return request.getAsync('http://localhost:3000/').spread(function(result, content) {
         //do something with content and then return first_promise
         console.log(content);
         return first_promise();
     })

And in some cases you don't need to create new promises at all

for Eg.

function inner_async_request(url_from_first_promise) {
    return request.getAsync(url_from_first_promise).spread(function(response, content) {
        final_result = content;
        return content;
    })
}

Finally, to make your test work, you need to modify this as well

    .then(function(url) {
        // return 
        return inner_async_request(url).then(function(result) {
            console.log(result);
            final_result = result;
            return second_promise(); // return second promise inside then
        })
    })

DEMO

code-jaff
  • 9,230
  • 4
  • 35
  • 56
  • Yes test passes but I still have some concerns. In this solution, isn't `return second_promise();` is dependent on execution of `inner_async_request()`? I want inner_async_request to be executed async and independently. – scaryguy Apr 20 '15 at 22:44
  • 1
    yes, in your code it runs independently. But you can't predict when that'll be resolved as long as it hasn't been chained somehow, therefore `final_result` too. Hence `expect(final_result).not.to.be.undefined;` likely to fail always. I hope it makes sense. – code-jaff Apr 21 '15 at 04:17
  • So what is the proper way of what I am looking for you think? I want an asynchronous job -which should run in the background without blocking the current promise- to be done while I still set the parent promise to be resolved. – scaryguy Apr 21 '15 at 07:54
  • 1
    In that case, since you are using *Bluebird*, you would be better off looking at [**Collections**](https://github.com/petkaantonov/bluebird/blob/master/API.md#collections) than tackling with individual promises. – code-jaff Apr 21 '15 at 08:04
  • 1
    I had already tried to make use of `.some` but had some issues with it during load testing. Well, thanks for follow up comments, I think I'd better ask another question once I have one which directly addresses my issue :) upvotes to you! :) – scaryguy Apr 21 '15 at 09:29