node.js asynchronous issue?

2019-09-14 16:37发布

问题:

Basically I want to loop through existing arrtickers to get each symbol

Then read the content inside each symbol url and save the content into local dir.

In php, it will print out each ticker and each symbol in step by step.

But in node, the sequences are mess up.

it will print out all the url_optionable first...

then sometimes print console.log('path: ' + file), sometimes print console.log("The file was saved!");

Everytime run through fs.writefile function, sym value is not detected, the saved file is show as msn-.html

for(var v=0;v<arrtickers.length;v++)
{
    var arrticker= arrtickers[v].split('@@');
    var sym= $.trim(arrticker[1]);

    url_optionable= "http://sample.com/ns/?symbol="+sym;

    console.log('url_optionable: ' + url_optionable);

    request({ uri:url_optionable }, function (error, response, body) {
      if (error && response.statusCode !== 200) {
        console.log('Error contacting ' + url_optionable)
      }

      jsdom.env({
        html: body,
        scripts: [
          jqlib
        ]
      }, function (err, window) {

        var $ = window.jQuery;
        var data= $('body').html();

        var file= "msn-"+sym+".html";
        console.log('path: ' + file);

        fs.writeFile(file, data, function(err) {
            if(err) {
            console.log(err);
            } 
            else 
            {
                console.log("The file was saved!");
                }
        });
      });
    });
}

回答1:

ZeissS is right. Basically, you can't use variables declared inside the for loop in a callback function to an asynchronous call, because they will all be set to the last value in the loop. So in your code, url_optionable and sym will correspond to arrtickers[arrtickers.length - 1].

Either use (as ZeissS suggests):

arrtickers.forEach(function(arrticker) {
    // Get symbol and url, make request etc
});

Or declare a function which takes sym and does the request, and call that in your loop:

function getSymbol(symbol) {
    // Request url and read DOM
}

for(var v=0;v<arrtickers.length;v++) {
    var arrticker = arrtickers[v].split('@@');
    var sym = $.trim(arrticker[1]);

    getSymbol(sym);
}

Personally, I would opt for the forEach solution.