http请求方法中的回调 - 没有按正确的顺序发生

时间:2016-07-13 00:33:00

标签: javascript node.js

我编写了一个程序,为三个不同的URL发出HTTP GET请求。该程序应该按照提供的URL的顺序输出消息正文,但是即使我按照这个顺序进行回调,它也不会这样做。

最终的程序应该要求用户通过命令行输入URL,但是我只是为了便于测试而进行了变量赋值。

我意识到这段代码可能更加面向对象 - 但是我是JavaScript的新手,现在学习的不是我的重点

var http = require('http')

// var url_1 = process.argv[2]
// var url_2 = process.argv[3]
// var url_3 = process.argv[4]

var url_1 = 'http://youvegotmail.warnerbros.com/cmp/0frameset.html'
var url_2 = 'http://www.3riversstadium.com/index2.html'
var url_3 = 'http://toastytech.com/evil/'

var output_1 = ''
var output_2 = ''
var output_3 = ''


function getHttp_1 (callback) {
    http.get(url_1, function getResponse (response1) {
        response1.setEncoding('utf8')
        response1.on('data', function (data) {
            output_1 = output_1 + data
        })
        response1.on('end', function processData() {
            console.log("Printing Result 1:")
            callback(output_1)
        })
    })
}

function getHttp_2 (callback) {
    http.get(url_2, function getResponse (response2) {
        response2.setEncoding('utf8')
        response2.on('data', function (data) {
            output_2 = output_2 + data
        })
        response2.on('end', function processData() {
            console.log("Printing Result 2:")
            callback(output_2)
        })
    })
}

function getHttp_3 (callback) {
    http.get(url_3, function getResponse (response3) {
        response3.setEncoding('utf8')
        response3.on('data', function (data) {
            output_3 = output_3 + data
        })
        response3.on('end', function processData() {
            console.log("Printing Result 3:")
            callback(output_3)
        })
    })
}

function printResults(output) {
    console.log("Result")
    // console.log(output)
}

getHttp_1(printResults)
getHttp_2(printResults)
getHttp_3(printResults)

编辑:

结果我通常会得到:

Printing Result 3:
Result
Printing Result 2:
Result
Printing Result 1:
Result

我期待的结果:

Printing Result 1:
Result
Printing Result 2:
Result
Printing Result 3:
Result

4 个答案:

答案 0 :(得分:3)

与某些答案提出的顺序回调方法相比,使用Promise s将使这更有效(请求将并行)并且更简单:

var http = require('http'),
    urls = [
        'http://youvegotmail.warnerbros.com/cmp/0frameset.html',
        'http://www.3riversstadium.com/index2.html',
        'http://toastytech.com/evil/'
    ];

Promise.all(urls.map(getUrl))
       .then(function (results) {
            results.forEach(function (output, i) {
                console.log("Result #" + (i + 1) +
                            " with length: " + output.length);
            });
       });

function getUrl(url, i) {
    return new Promise(function (resolve, reject) {
        http.get(url, function getResponse(resp) {
            var output = '';
            resp.setEncoding('utf8');
            resp.on('data', function (data) {
                output += data;
            });
            resp.on('end', function processData() {
                console.log("Resolving Result " + (i + 1) + ":");
                resolve(output);
            });
        })
    });
}

答案 1 :(得分:2)

欢迎来到node.js的异步生活!当您触发这些HTTP请求时,不会等待请求在它发出之前完成。您看到这种奇怪的行为,因为您实际上是一次发送所有3个请求,只是在您看到响应时打印。

编辑:如果您确实希望以正确的顺序查看它们,请在第一个回调中启动第二个HTTP请求,然后在第二个回调内部启动第三个HTTP请求。这样可以保证在完成数据之前不会获得数据。

function getHttp_1 (callback) {
    http.get(url_1, function getResponse (response1) {
        response1.setEncoding('utf8')
        response1.on('data', function (data) {
            output_1 = output_1 + data
        })
        response1.on('end', function processData() {
            console.log("Printing Result 1:")
            callback(output_1)
            getHttp_2(callback)
        })
    })
}

答案 2 :(得分:2)

async module可以真正帮助控制异步任务的执行方式。例如,如果您希望您的请求一个接一个地发生:

async.series([
  function (next) { makeRequest(url_1, next); },
  function (next) { makeRequest(url_2, next); },
  function (next) { makeRequest(url_3, next); },
], function (err, result) {
   // All done
});

// Or you can get fancy
//async.series([
//  makeRequest.bind(null, url_1),
//  makeRequest.bind(null, url_2),
//  makeRequest.bind(null, url_3),
//]);

function makeRequest(url, callback) {
  http.get(url, function getResponse (res) {
      var output = '';
      res.setEncoding('utf8')
      res.on('data', function (data) {
          output += data
      })
      response1.on('end', function processData() {
          callback(output)
      })
  })
}

如果您不关心它们发生的顺序,但希望按顺序输出它们:

async.parallel([
  function (next) { makeRequest(url_1, next); },
  function (next) { makeRequest(url_2, next); },
  function (next) { makeRequest(url_3, next); },
], function (err, results) {
  if (err) {
    return void console.error('Got an error:', err.stack);
  }

  console.log(results); // Will output array of every result in order
});

如果请求相互依赖,async.auto可以将一个请求的结果与另一个请求的结果联系起来。

答案 3 :(得分:0)

JavaScript / AJAX调用是异步的,因此请不要按照您调用的顺序进行操作。要按顺序/特定顺序调用它们,请执行以下操作:

$(function () {

//setup an array of AJAX options, each object is an index that will specify information for a single AJAX request
var ajaxes  = [{ url : '<url>', dataType : 'json' }, { url : '<url2>', dataType : 'utf8' }],
    current = 0;

//declare your function to run AJAX requests
function do_ajax() {

    //check to make sure there are more requests to make
    if (current < ajaxes.length) {

        //make the AJAX request with the given data from the `ajaxes` array of objects
        $.ajax({
            url      : ajaxes[current].url,
            dataType : ajaxes[current].dataType,
            success  : function (serverResponse) {
                ...
                //increment the `current` counter and recursively call this function again
                current++;
                do_ajax();
            }
        });
    }
}

//run the AJAX function for the first time once `document.ready` fires
do_ajax();
});

另一种选择可能是:

function callA() {
$.ajax({
...
success: function() {
  //do stuff
  callB();
}
});
}

function callB() {
    $.ajax({
    ...
    success: function() {
        //do stuff
        callC();
    }
    });
}

function callC() {
    $.ajax({
    ...
    });
}


callA();

参考:Multiple Calls in Order