我正在尝试使用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()
在我的实际代码中,items数组是在运行时生成的。我希望这段代码能提供google.com和yahoo.com的截图,但实际上这两个屏幕截图最终都是yahoo.com。我觉得这与在循环中创建闭包有关,但我看不出如何。调用open
时,item
引用特定字符串。我永远不会关闭它,是吗?
答案 0 :(得分:1)
问题是casper.open
没有添加步骤,因此它不是异步的(如thenOpen
)。它立即在外部then
内执行。但是以下then
是异步的,因此添加其步骤以在当前步骤(外部then
)之后执行。两个open
都被执行,但两个then
的回调都在最后open
之后执行。
因此解决方案是使用thenOpen
作为组合异步步骤。 Straigt正向解决方案存在一些问题:
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.open
和casper.then
合并到casper.thenOpen
并通过IIFE传递item
和idx
,以便将它们固定到每次迭代:
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'