为什么要算回调?

时间:2015-10-17 15:02:25

标签: javascript node.js callback

我正在研究问题10:learnyounode教程中的ASYNC JUGGLING。

  

此问题与上一个问题(HTTP COLLECT)相同   你需要使用http.get()。但是,这次你会   提供了三个URL作为前三个命令行参数。

     

您必须收集每个提供给您的完整内容   URL并将其打印到控制台(stdout)。你不需要打印出来   长度,只是作为字符串的数据;每个网址一行。问题是   您必须按照与URL相同的顺序打印出来   作为命令行参数提供给你。

官方解决方案涉及计算回调:

$sql = "SELECT p.catid, p.catname, p.productid, p.prodimg, 
            GROUP_CONCAT(p.prodsize ORDER BY p.id ASC) as size, 
            GROUP_CONCAT(p.cost ORDER BY p.id ASC) as cost, p.prodname,
            GROUP_CONCAT(c.prodsize,'-',c.quantity) as cart_details, 
            GROUP_CONCAT(DISTINCT(c.userid)) as user_id,
            SUM(CASE WHEN c.status = 'add_to_cart' THEN quantity ELSE 0 END) AS quantity
        FROM productsize p
        LEFT JOIN cart c ON(c.productid = p.productid 
            AND p.prodsize = c.prodsize)
            AND c.userid = {$userid}
        WHERE p.catid = {$catid}
        GROUP BY p.productid, c.status
        ORDER BY p.productid ASC";

程序必须等到收到所有三个响应后再打印出来,这样它们才会按照输入的顺序出现。

我的尝试涉及使用回调来确保正确的顺序:

var http = require('http')
var bl = require('bl')
var results = []
var count = 0

function printResults () {
  for (var i = 0; i < 3; i++)
    console.log(results[i])
}

function httpGet (index) {
  http.get(process.argv[2 + index], function (response) {
    response.pipe(bl(function (err, data) {
      if (err)
        return console.error(err)

      results[index] = data.toString()
      count++

      if (count == 3) // yay! we are the last one!
        printResults()
    }))
  })
}

for (var i = 0; i < 3; i++)
httpGet(i)

但这会三次吐出var http = require('http') var bl = require('bl') var results = [] function printResults () { console.log(results[0]) console.log(results[1]) console.log(results[2]) } function httpGet (i) { http.get(process.argv[2 + i], function (response) { response.pipe(bl(function (err, data) { if (err) return console.error(err) results[index] = data.toString() })) }) } function httpGetAll (callback) { httpGet(0) httpGet(1) httpGet(2) callback() } httpGetAll(printResults) 。所以似乎在执行三个undefined行之前调用了printResults()。似乎我不理解回调和我的想法。

所以我的问题是,有没有办法在httpGet()上使用回调来实现这个目标?或者我来计算httpGetAll()的回调?

1 个答案:

答案 0 :(得分:1)

  

但这三次吐出未定义。因此,似乎在执行三个httpGet()行之前调用了printResults()。好像我不理解回调以及我的想法。

是的,您误解了异步代码的行为方式。首先执行三个httpGet() ARE,但是直到稍后的事件循环滴答时才会执行具有结果的异步回调。如果查看httpGet,缩进1级的代码将在第一个刻度上运行,这实际上就是第一行,嵌套回调函数中缩进2级的所有代码都不会在同一个刻度上执行。该代码仅在事件队列上安排,以便稍后在HTTP响应到达之后,但节点不等待,它会继续进行过渡。

  

所以我的问题是,有没有办法在httpGetAll()上使用回调来实现这个目的?或者我是否必须将回调计入httpGet()?

是的,有一些方法可以正确实现这一点而无需专门计算回调,但是,您必须&#34;跟踪&#34;以某种方式挂起的电话。计数是一种简单有效的方法,但您也可以将数组用作待处理调用的队列,在每个响应到达时从队列中删除一个元素,并在队列为空时知道您已完成。您还可以使用done属性跟踪每个请求的对象状态,该属性以false开始,并在响应到达时设置为true,并通过确保所有操作检查是否全部完成done属性为true。它在技术上并不重要,但它具有类似性质的簿记。