在 Casperjs 中循环访问 URL

Looping over URLs in Casperjs

我正在尝试使用 Casperjs 按顺序打开几个 URL。

这是我实际代码的简化版本。

casper = require('casper').create()
casper.start()

casper.then () ->
  items = ['http://www.google.com', 'http://www.yahoo.com']

  for item, idx in items
     this.open item
     this.then ((idx) ->
        () ->
            this.capture idx + '.png')(idx)

casper.run()

在我的实际代码中,项目数组是在运行时生成的。我希望此代码将提供 google.com 和 yahoo.com 的屏幕截图,但实际上这两个屏幕截图最终都是 yahoo.com。我觉得这与在循环内创建闭包有关,但我看不出如何。当调用 open 时,item 引用特定的字符串。我永远不会结束它,是吗?

问题在于 casper.open 没有添加步骤,因此它不是异步的(如 thenOpen)。它立即在外部 then 内部执行。但是下面的then异步的,所以它的步骤被添加到当前步骤之后执行(外部then)。两个 open 都执行了,但是两个 then 的回调都在最后一个 open.

之后执行

因此解决方案是使用 thenOpen 作为组合的异步步骤。直接解决方案有一个小问题:

CoffeeScript is a little language that compiles into JavaScript.

这意味着 JavaScript 存在误解。这是一个:JavaScript closure inside loops – simple practical example

for item, idx in items 行仍然是 for loop in JavaScript。 JavaScript 具有函数级别范围,casper.then 是一个异步步骤函数,这意味着所有 casper.then 调用的回调在循环 运行 完全通过(更准确地说当前步骤完成后或调用 casper.run 后),但立即执行 casper.open

解决方案:将 casper.opencasper.then 合并为 casper.thenOpen 并通过 IIFE 传递 itemidx 以便它们在每次迭代中固定:

for item, idx in items
    ((item, idx) ->
        casper.thenOpen item, () ->
            this.capture idx + '.png'
    )(item, idx)

或使用Array.prototype.forEach:

items.forEach (item, idx) ->
    casper.thenOpen item, () ->
        this.capture idx + '.png'