有条件地在for循环中的异步函数调用中执行回调

时间:2011-08-11 03:02:51

标签: javascript asynchronous node.js closures

我正在研究一个迭代一系列端口的函数,并在其中一个端口可用后调用它的回调。我不想等待每个端口响应,而是想在所有端口上调用checkPortStatus函数,并在第一个端口返回时返回。

以下是node.js中可运行的示例代码:

    // Check if a port is open (in use) or closed (available)
    function checkPortStatus(port, callback) {
      // Simulates real world checking of response from port by returning
      // after a random time.
      setTimeout(function() {
        // Simulates a few closed ports
        if (port === 3005 || port === 3006 || port === 3007) {
          callback('closed')
        }
        // Simulates a few open ports
        else {
          callback('open')
        }
      }, Math.floor(Math.random() * 200))
    }

    // Calls callback once any available port is found
    function findAnAvailablePort(startPort, endPort, callback) {
      var check = function(port) {
        checkPortStatus(port, function(status) {
          // If a port is 'closed', it's considered available
          if (status === 'closed') {
            callback(port)
          }
        })
      }
      for (var port = startPort; port <= endPort; port++) {
        check(port)
      }
    }

    findAnAvailablePort(3000, 3010, function(port) {
      console.log('AVAILABLE PORT: ' + port)
    });

    // Don't exit Node, wait for a response
    setTimeout(function() { console.log('FIN') }, 5000)

运行代码的结果:

AVAILABLE PORT: 3005
AVAILABLE PORT: 3007
AVAILABLE PORT: 3006

两个问题:

  1. 如何只召回一次回调?我只想要匹配的第一个端口返回。
  2. 如何检查是否返回了所有函数回调?在此示例中,我需要在所有checkPortStatus将端口返回为不可用时返回。

1 个答案:

答案 0 :(得分:1)

初始化函数之外的一些变量应该可以解决问题:

// Calls callback once any available port is found
var hasFoundPort = false;
var checkedPorts = 0;
function findAnAvailablePort(startPort, endPort, callback) {
  var check = function(port) {
    checkPortStatus(port, function(status) {
      checkedPorts++;
      // If a port is 'closed', it's considered available
      if (status === 'closed' && !hasFoundPort) { // only execute callback once
        callback(port)
        hasFoundPort = true;
      }
      if(checkedPorts == endPort - startPort + 1) // checked all ports
          console.log('finished checking');
    })
  }
  for (var port = startPort; port <= endPort; port++) {
    check(port)
  }
}