【问题标题】:How to transform synchronous style code to asynchronous code?如何将同步样式代码转换为异步代码?
【发布时间】:2012-09-30 23:51:14
【问题描述】:

我有一些看起来像这样的同步代码:

function bulk_upload(files, callback) { 
  for (file in files) {
   sync_upload(file); // blocks till file uploads
  }
  print('Done uploading files');
  callback();
}

我现在必须使用异步 API async_upload(file, callback) 而不是 sync_upload(file) 来做同样的事情。我有多种选择,但不确定什么是最好的:

1) 在 for 循环之后使用 sleep - 这是一个 hack,因为我希望我的时机是正确的

2) 递归链接我的数组:

function bulk_upload(files, callback) {
  if (files.length == 0) {
    print('Done uploading files');
    callback();
  } else {
    async_upload(files.removeLast(), function() { bulk_upload(files, callback); });
  }
}

这不仅是 hacky,而且是次优的,因为我可以使用新的 async_upload API 并行上传我的文件,但我最终按顺序上传。

3) 使用全局计数器:

function bulk_upload(files, callback) {
  uploads = 0
  for(file in files) {
    async_upload(file, function() { uploads++; }); 
  }
  while(uploads < files.length) ; // Empty spin - this is stupid
  print('Done uploading files');
  callback();
}

4) 稍微好一点的计数器(但仍然很糟糕):

function bulk_upload(files, callback) {
  uploads = 0
  for(file in files) {
    async_upload(file, function() { 
      if (++uploads == files.length) { // this becomes uglier as I want to await on more stuff
        print('Done uploading files');
        callback();
      }; 
    }); 
  }
}

【问题讨论】:

  • 您可以使用期货来实现这一点。 [这里][1] 有一个很好的例子。 [1]:stackoverflow.com/questions/5989538/…
  • 期货答案是最干净的方式,而您的 4) 是另一种 mroe 标准方式,尽管通常包含在帮助程序中。我只是想指出你的 1) 和 3) 无论如何都行不通。你的自旋锁永远不会完成,因为 Javascript 使用单线程,所以当你的 while 循环时,上传回调不可能运行。
  • 请注意,选项 3) 不可行;在紧密循环中阻塞将阻止任何async_uploads 回调运行,因此您将无限循环。

标签: node.js design-patterns asynchronous callback synchronous


【解决方案1】:

您可以使用async 模块的forEach 方法来执行此操作:

function bulk_upload(files, callback) {
    async.forEach(files, async_upload(file, callback), function (err) {
        if (err) {
            console.error('Failed: %s', err);
        } else {
            console.log('Done uploading files');
        }
        callback(err);
    });
}

【讨论】:

    【解决方案2】:

    根据我的评论,看起来这段代码使用期货(未经测试)就足够了。

    function aync_upload_promise(file) {
        // create a promise.
        var promise = Futures.promise();
        async_upload( file, function(err, data) {
            if (err) {
                // break it
                promise.smash(err);
            } else {
                // fulfill it
                promise.fulfill(data);
            }
        });
        return promise;
    }
    
    var promises = [];
    for(var i=0; i<files.length; ++i )
    {
       promises.push( aync_upload_promise( files[i] ) );
    }
    
    Futures
       .join( promises )
       .when( function() {
          print('Done uploading files');
          callback();
       } )
       .fail( function(err) { print('Failed :(', err); } )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-24
      • 2023-03-12
      • 1970-01-01
      • 2015-10-24
      • 1970-01-01
      • 2017-05-19
      • 2019-02-23
      • 1970-01-01
      相关资源
      最近更新 更多