0

I'm very new to async languages like nodejs, I'm trying to write a web scraper that will visit a link, download a code, extract with regex, THEN visit another link using that code. I'm aware I could use callbacks, but I expect to have to go 8-9 levels deep, I think promises is the way to go (is there a better way?)

var promise = require("promise");
var request = require("request");

login();

function get_login_code()
{
    request.get("someurl.com", function (error, response, body)
    {
        // just for example
        body = 'TOKEN" value="hello world"';
        var login_code = body.match(/.TOKEN" value="([^"]+)../i);
        return login_code
    });
}

function login()
{
    var login_promise = promise.resolve(get_login_code());
    console.log(login_promise);

}

I've tried a bunch of combinations of messing around with promises, but I either always get undefined or a promise which doesn't have a value. I don't want to nest promise functions inside promises because that's exactly the same thing as callback hell. Can someone tell me what I'm doing wrong, I really want this code to be procedural and not 8 callbacks. In the ideal world promise.resolve just waits until get_login_code() returns the actual code, not undefined.

Output:

Promise { _45: 0, _81: 1, _65: undefined, _54: null }

Desired Output:

hello world
Keatinge
  • 4,330
  • 6
  • 25
  • 44
  • I'd suggest you read [How to return response from asynchronous operation](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) which will show you to folly of `return login_code` and then read up a lot more about promises. Promises don't have magic powers to somehow know when an asynchronous operation is done. If you want a promise to resolve, you have to create the promise and call `resolve()` on it. – jfriend00 Jan 11 '17 at 09:47

2 Answers2

2

What your code do:

  • calls get_login_code that returns nothing (i.e. undefined)
  • inside of login function you create a new promise that is immediately resolved to the result of get_login_code, i.e. undefined.

Thus, you do not use login_code at all.

To make it work, you should make get_login_code to return a promise that will be resolved to login_code. Consider you use promise npm module, the code may look like:

// uppercased, it's a constructor
var Promise = require("promise");
var request = require("request");

login();

function get_login_code()
{
    return new Promise(function (resolve, reject) {
      request.get("someurl.com", function (error, response, body) {
        if (err) {
            reject(err);
            return;
        }
        // just for example
        body = 'TOKEN" value="hello world"';
        var login_code = body.match(/.TOKEN" value="([^"]+)../i);
        resolve(login_code);
      });
    });
}

function login()
{
    // return a new promise to use in subsequent operations
    return get_login_code()
        .then(function(login_code) {
            console.log(login_code);
        });
}
Sergey Lapin
  • 2,633
  • 2
  • 18
  • 20
  • It would be better to generically promisify just `request.get()` and then use that in `get_login_code()`. They the promisified function can be reused for lots of operations. Always best to promisify at the lowest level possible and then use the promise implementation at higher levels. Makes more reusable code and generally cleaner code. – jfriend00 Jan 11 '17 at 09:48
1

You should create new promise in the function to handle reject and resolve not by handling resolve to the function itself. Use then to get the response value from promise. I guess this should work.

var promise = require("promise");
var request = require("request");


function get_login_code()
{
    var promise = new Promise(function(resolve, reject) {
          request.get("someurl.com", function (error, response, body)
          {
             if (error) {
                 reject(error);
             } else {
                 // just for example
                 body = 'TOKEN" value="hello world"';
                 var login_code = body.match(/.TOKEN" value="([^"]+)../i);
                 resolve(login_code);
             }
          });
    });       
}

get_login_code()
        .then(function (code) {
      console.log(code);
});
digit
  • 4,479
  • 3
  • 24
  • 43