0

Im writing little scrap tool with Node(Express) searching urls from list. Problem is with access to results of search outside of request callback function in forEach loop. Please help - why results array are empty outside request? I want exports this results to the view. Also any variable defined inside request is not defined from outside. Here my code:

var express = require('express');
var request = require('request');
var bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({ extended: false });
var fs = require("fs");
var app     = express();


app.get('/scrap/',function(req,res){
    res.render('start.ejs');

});

app.post('/scrap/result', urlencodedParser, function(req,res){

        var lista = req.body.lista;
        var phrase = req.body.phrase;        
        var l = lista.split('\n');
        var results = [];  // declaring results array       

        l.forEach(function(elem) {            

            request(elem, function(error, response, html) {

                try {
                if (html.indexOf(phrase) > 0) {
                var result = 'Phrase "' + phrase + '" found';
                }
                else {
                  var result = 'Phrase "' + phrase + '" not found';
                }                

              }
              catch(err) {
                var result = 'Error: '+ err.message;
              }
             results.push(result);             

             console.log(results) // here results array is filled with result

            });
           console.log(results); // results array is empty

        });  

         console.log(results); // results array is also empty

            res.render('result.ejs', { 
                  result : results[0],
                  phrase : phrase, 
            });     

}); 


app.use(function(req, res, next){
    res.redirect('/scrap');
});

app.listen(3000);

1 Answers1

0

instead of a forEach use a map, and return an array of promises, then qait on all of them before providing the response.

var responsePromises = l.map(geturslResponsePromise)
q.all(responsePromises).then(function(results){
     res.render('result.ejs', { 
         result : results[0],
         phrase : phrase, 
     });     
})

Where geturslResponsePromise is somethign to the effect

var geturslResponsePromise = function(elem) {
   return new Promise(function(resolve, reject){

     request(elem, function(error, response, html) {
        try {
            if (html.indexOf(phrase) > 0) {
                resolve('Phrase "' + phrase + '" found');
            }
            else {
                resolve('Phrase "' + phrase + '" not found');
            }                
        }
        catch(err) {
            reject('Error: '+ err.message);
        }

    }) // request
   }) // promise
}

note: untested code, probably a ton of bugs, but that is the approach I would take with an ES5 based syntax

note2: I would also recommend more meaningful variable names. Things like Request, Responses, Url, Uri are fairly well known and understaood in the web space

akaphenom
  • 6,728
  • 10
  • 59
  • 109