【问题标题】:Calling done on an array of http.get requests in Node.js在 Node.js 中对一组 http.get 请求调用 done
【发布时间】:2014-06-09 17:13:23
【问题描述】:

我有一个 URL 数组,我使用 for 循环调用 http.get 请求。由于这是一个异步进程,我想在所有请求都返回后调用 done。

这是我目前的尝试:

grunt.registerTask('verify', function() {
    var done = this.async();
    var promises = [];
    var urlPrefix = 'http://example.com/';
    for(var i = 0; i < deployableFiles.length; i++) {

        (function(i) {
            var deferred = Q.defer();
            promises.push(deferred);
            var file = deployableFiles[i];
            var path =  file.filetype + '/' + getVersionedFileName(file.basename, file.filetype);
            http.get(urlPrefix + path, function(res) {
                deferred.resolve();
                if(res.statusCode === 200) {
                    grunt.log.oklns(path + ' was found on production server.');
                } else {
                    grunt.log.error('Error! ' + path + ' was not found on production server!');
                }
            }).on('error', function(e) {
                grunt.log.error("Got error: " + e.message);
                done();
            });
        })(i);
    }

    Q.all(promises)
    .done(function() {
        // Everything executed correctly
        return done();
    }, function(reason) {
        // There was an error somewhere
        return done(false);
    });
});

我确定只是我没有正确理解节点的整个异步性质,但有什么对其他人来说显而易见的事情吗?

我搜索了有关在 Q 库中使用 http 的信息,看来可能需要使用 Q.nfcall 才能使其工作。我只是无法理解为什么我必须这样做。 (我并不反对实际这样做,我比其他任何事情都更好奇)

谢谢!

【问题讨论】:

  • 您能否更明确地说明您面临的问题?你期望它做什么,它实际上在做什么?

标签: javascript node.js promise q


【解决方案1】:

如果这不是错字,promises.push(deferred) 应该被推送到承诺 promises.push(deferred.promise)

function foo() {
  ...
  return defer.promise;
}

// => foo().then(function() ...);

Q.all([
  foo(),
  foo(),
  ...
]).done(function() ...);

Q.all 需要一系列承诺。 https://github.com/kriskowal/q#combination


Q.nfcall 只是如果

使用使用 Node.js 回调模式的函数,其中回调的形式为 function(err, result)

https://github.com/kriskowal/q#adapting-node

【讨论】:

  • 感谢您在 Q.nfcall 上的快速回答和信息。你是对的,我的打字速度太快了,当我推到我的延迟数组时,我离开了“承诺”。
【解决方案2】:

您应该始终在可能的最低级别执行承诺。这使得对并发性的推理变得容易得多。

function getPing(url){
    return new Q.Promise(function(resolve,reject){
         http.get(url,function(res){
             // note this will _not_ wait for the whole request
             // but just the headers.
             if(res.statusCode === 200) resolve();
             else reject();
         });
    });
}

这会让你这样做:

grunt.registerTask('verify', function() {
    var done = this.async();
    var urlPrefix = 'http://example.com/';
    var pings = deployableFiles.map(function(file){
        var path =  file.filetype + '/' + 
                        getVersionedFileName(file.basename, file.filetype);
        return getPing(urlPrefix + path);
    });
    Q.all(pings).then(done).catch(function(reason) {
        // There was an error somewhere
        // this will happen as soon as _one_ promise rejected
        return done(false);
    });
});

这可以通过使用像 Bluebird 这样更好的 Promise 库来进一步缩短。

【讨论】:

  • 我非常喜欢你的思维方式。由于您的解决方案是我使用的解决方案,因此我将您的解决方案标记为正确。虽然我也看到了其他答案中的价值。
【解决方案3】:

您也可以使用async

var urlPrefix = 'http://example.com/';
async.each(deployableFiles, function(file, cb) {
  var path =  file.filetype
              + '/'
              + getVersionedFileName(file.basename, file.filetype);
  http.get(urlPrefix + path, function(res) {
    if (res.statusCode === 200)
      grunt.log.oklns(path + ' was found on production server.');
    else
      grunt.log.error('Error! ' + path + ' was not found on production server!');
    cb();
  }).on('error', function(e) {
    grunt.log.error("Got error: " + e.message);
    cb(e);
  });
}, function(err) {
  // all done

  if (err) throw err;

  // all successful
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-25
    • 2018-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-22
    • 2019-01-25
    相关资源
    最近更新 更多