0

我使用zombie.js库,对dom做一些测试,我有这个脚本

Browser = require "zombie"
arr = new Array("http://yahoo.com", "http://google.com", "http://msn.com")
i = 0
while i < arr.length
    b = new Browser()
    b.visit arr[i], ->
        console.log b.text "title"
    b.close()
    i++

一切正常,但它只记录两次 msn 标题,因此 while 循环将数组中的最后一项记录两次。我似乎看不出问题出在哪里?

4

3 回答 3

2

您正在注册浏览器visit完成时的回调。到那时,循环已经运行完成,因此变量b指向您创建的最后一个浏览器,这意味着它的标题将是 MSN 的标题,而不是其他页面的标题。为了解决这个问题,使用闭包:

Browser = require "zombie"
arr = new Array("http://yahoo.com", "http://google.com", "http://msn.com")
i = 0
createBrowser = (url) ->
    b = new Browser()
    b.visit url, -> console.log b.text "title"
    b.close()

while i < arr.length
    createBrowser(arr[i++])

这是有效的,因为现在您创建的每个浏览器都有一个单独的范围,以及一个单独的浏览器变量。

或者,使用 ZombieJSvisit函数的回调参数:

Browser = require "zombie"
arr = new Array("http://yahoo.com", "http://google.com", "http://msn.com")
i = 0
while i < arr.length
    b = new Browser()
    b.visit arr[i], (e, myBrowser) ->
        console.log myBrowser.text "title"
    b.close()
    i++
于 2013-01-21T13:22:07.807 回答
1

visit方法是异步的,采用回调函数。换句话说,visit在任何日志记录发生之前调用了 3 次,即在和调用之间执行console.log。到最后一个回调完成时,指的是“最后一个”浏览器实例(msn 实例)。该方法可能会传递回调的结果,请查看文档。b.visitb.closebvisit

Browser = require 'zombie'

for url in ["foo", "bar", "baz"] # elegant way to loop lists in coffeescript
  b = new Browser
  b.visit url, (err, b) ->       # b given as argument masks the b in outer scope
    console.log b.text "title"
    b.close()
于 2013-01-21T13:10:37.783 回答
1

我认为您想要做的是类似于以下内容(警告,未经测试!):

Browser = require "zombie"
sites = ['http://yahoo.com', 'http://google.com', 'http://msn.com']

process = (site) ->
  b = new Browser()
  b.visit site, () ->
    title = b.text title
    console.log title
    b.close()

process site for site in sites

我冒昧地更改了一些零碎的东西-希望它仍然很清楚。

如果您不习惯 JavaScript(和 CoffeeScript),它们会有奇怪的作用域规则。我发现通常最好在一个函数中完成所有工作,以使事情按您的预期工作。

我不确切地知道zombie.js 是如何工作的,但我认为这应该如你所愿。

于 2013-01-21T13:27:55.637 回答