6

有一个动态值可能从小到大的 for 循环,我想确保在下一个调用开始之前完成一个搜索调用。我怎么做?我已经阅读了有关 process.nextTick 和 setImmediate 的信息,但我不确定如何在这种情况下使用它们。

function search(x) {
      dns.resolve(x, function (err, addresses) {
           if (!err) {
                res.send("bad");
           } else {
                res.send("good");
           }
      });
}

for(a = 0; a < queries.length; a++) {
    query = queries[a];
    search(query);
}
4

3 回答 3

7

有一些库可以帮助您组织异步代码的执行。 Async是我使用的,它的eachSeries()在这里很有用:

function search(x,callback) {
  dns.resolve(x, function (err, addresses) {
    if (!err) {
      res.send("bad");
    } else {
      res.send("good");
    }
    callback(err);
  });
}

async.eachSeries(queries,
  function(query,callback) {
    search(query,callback);
  },
  function(err) {
    if(err) {
      console.log("we had an error");
    }
  }
);

请注意,只要其中一个迭代出现错误,Async 就会调用最终回调,因此如果您不想停在那里,则需要调用callback()insearch()而不是callback(err).

更新(不使用库):

如果你不想使用库,你可以像这样自己实现它:

function searchInternal(queries, idx, callback) {
  if(idx === queries.length) {
    callback();
    return;
  }

  dns.resolve(queries[idx], function (err, addresses) {
    if (!err) {
      res.send("bad");
    } else {
      res.send("good");
    }
    searchInternal(queries, idx+1, callback);
  });
}

function searchAll(queries, callback) {
  searchInternal(queries, 0, callback);
}

searchAll(queries, function() {
  console.log("all done now");
});

请注意,此代码未经测试,可能不是最佳实现,但这就是我们使用库的原因。

于 2013-07-30T00:04:47.353 回答
3

我通常只使用事件发射器使其全部同步,因此我仍然可以在异步环境中工作。在我下面的代码中,每当 DNS 解析完成时,它都会产生一个事件,由搜索函数监听并让它知道触发新的搜索。此外,您还可以学习如何创建自己的事件发射器,这非常棒。

如果要使其对一定大小的域名数组异步,可以创建一个分母变量并使用模运算符以块的形式发送异步,并且仅在模数达到时触发同步事件(以清除异步缓冲区) 0。

// program that uses event emitters to create sync code in an async env

var dns = require('dns')                                //dns from core
var eventEmitter = require('events').EventEmitter       //Event Emitter from core

var ee = new eventEmitter;      //make an Event Emitter object

var queries = ['yahoo.com','google.com','james.com'];

ee.on('next', next_search);     //create a listener for an event we define

// our listening function that executes on our defined 'next' event
function next_search() {
        search(queries[a]);
        if(queries.length == a) process.exit(0);
        ++a;
}

// the actual search function that uses DNS
function search(x) {
        dns.resolve(x, function (err) {
                if (!err) {
                        //res.send("bad");
                        console.log('bad: ' + x)
                        ee.emit('next')
                } else {
                        //res.send("good");
                        console.log('good: ' + x)
                        ee.emit('next')
                }
        });
}


// global variable to keep track of our name queue length
var a = 0;

// kick it all off
next_search()
于 2013-07-30T08:34:44.740 回答
2

我最近创建了一个更简单的抽象,称为wait.for以在同步模式下调用异步函数(基于节点光纤)。它是在:

https://github.com/luciotato/waitfor

使用wait.for,您可以调用 dns.resolve 以按顺序执行。

wait.for允许您调用任何标准的 nodejs 异步函数,就好像它是一个同步函数一样,而不会阻塞节点的事件循环。您可以在需要时按顺序编码。

使用wait.for您的代码将是:

for(a = 0; a < queries.length; a++) {
  try {
    addresses = wait.for(dns.resolve,queries[a]);
    res.send('good');
  }
  catch(err){
    res.send('bad');
  }

}//end for
于 2013-08-28T03:44:43.773 回答