我可以重构嵌套的async.each循环吗?

时间:2013-12-29 12:19:25

标签: javascript asynchronous coffeescript

我在coffeescript中写了一个缓存加温工具。我们有2个目标服务器,5个站点,每个站点1000个页面,每页3个版本。所以总共有30k的请求。我正在使用async.eachasync.eachLimitasync.eachSeries,而且效果很好。但是,代码变得有点难以阅读。我看过async.waterfall并承诺,但这看起来不会有所帮助。

work = () ->
  async.each config.targets, (target, callback) ->
    async.eachLimit sitemaps, config.concurrency.sitemaps, (sitemap, callback) ->
      async.eachLimit sitemap, config.concurrency.urls, (url, callback) ->
        async.eachSeries config.requests, (req, callback) ->
          doRequest target, sitemap, url, req, callback
        , callback
      , callback
    , callback
  , (err) ->
      console.log "All done"

我有什么办法可以重做吗?

如果参数顺序为async.each array, callback, iterator,我会对上面的布局感到满意。但回调的语法有点难以阅读。

1 个答案:

答案 0 :(得分:0)

如何将函数定义拆分为自己的行?我还添加了括号,使函数调用更清晰(对我而言)。

work = () ->
  async.each( config.targets, (target, callback) ->
    async.eachLimit( sitemaps, config.concurrency.sitemaps, 
      (sitemap, callback) ->
        async.eachLimit( sitemap, config.concurrency.urls, 
          (url, callback) ->
            async.eachSeries( config.requests, 
              (req, callback) ->
                doRequest( target, sitemap, url, req, callback)
            , callback)
        , callback)
      , callback)
  , (err) ->
      console.log "All done"
  ) 

修改

理论上,一个或多个内部循环可以作为命名函数分解。例如:

foo1 = (sitemap, callback) ->
  async.eachLimit( sitemap, config.concurrency.urls,
    (url, callback) ->
      async.eachSeries( config.requests,
        (req, callback) ->
          doRequest( target, sitemap, url, req, callback)
      , callback)
  , callback)

work1 = () ->
  async.each( config.targets, (target, callback) ->
    async.eachLimit( sitemaps, config.concurrency.sitemaps,
      foo1
      , callback)
  , (err) ->
      console.log "All done"
  )
# error - target is not defined in doRequest(target...)

此处的问题是,target循环设置的work1不会通过foo1传递给doRequest

看起来async.apply可以用来解决这个问题

foo2 = (target, sitemap, callback) ->
  async.eachLimit( sitemap, config.concurrency.urls,
    (url, callback) ->
      async.eachSeries( config.requests,
        (req, callback) ->
          doRequest( target, sitemap, url, req, callback)
      , callback)
  , callback)

work2 = () ->
  async.each( config.targets, (target, callback) ->
    async.eachLimit( sitemaps, config.concurrency.sitemaps,
      async.apply(foo2, target)
      , callback)
  , (err) ->
      console.log "All done 2"
  )

或者将这种分区推向极致:

foo1 = (target, callback) ->
  async.eachLimit( sitemaps, config.concurrency.sitemaps
  , async.apply(foo2, target)
  , callback)

foo2 = (target, sitemap, callback) ->
  async.eachLimit( sitemap, config.concurrency.urls
  , async.apply(foo3, target, sitemap)
  , callback)

foo3 = (target, sitemap, url, callback) ->
  async.eachSeries( config.requests
  , async.apply(doRequest, target, sitemap, url)
  , callback)

work3 = () ->
  async.each(config.targets, foo1
  , (err) ->
    console.log "All done 3"
  )

其他绑定/部分方法可行

foo2.bind(null, target) # Javascript bind
_.partial(foo2, target) # lodash, underscore