我在普通js中有代码,其中事件处理程序更改全局变量而不传入它。
"use strict";
var outsideEventString ="hello";
console.log("before event " + outsideEventString);
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
/*
Assume a and b are outside your control,
but you still need to set the outsideEventString arg
*/
myEmitter.on('event', function(a, b) {
console.log(a, b, this);
console.log("inside event " + outsideEventString);
outsideEventString="goodbye";
});
myEmitter.emit('event', 'a', 'b');
// this prints out goodbye which is set in the handler only
console.log("after event " + outsideEventString);
将onDOMContentLoaded事件和处理程序添加到phantomjs示例netlog.js后,代码如下所示:
"use strict";
console.log("netlog.js");
var page = require('webpage').create(),
system = require('system'),
address;
var valueString = "hello";
var value1 = {
current: false,
timeStamp: null
};
if (system.args.length === 1) {
//console.log('Usage: phantomjs netlog.js <some URL>');
phantom.exit(1);
} else {
var PHANTOM_FUNCTION_PREFIX = '/* PHANTOM_FUNCTION */';
address = system.args[1];
page.onConsoleMessage = function(msg) {
if (msg.indexOf(PHANTOM_FUNCTION_PREFIX) === 0) {
eval('(' + msg + ')()');
} else {
console.log(msg);
}
};
page.onInitialized = function() {
// add handler & apply value1 to handler's scope'
page.evaluate(function(domContentLoaded) {
document.addEventListener('DOMContentLoaded', domContentLoaded, false);
}, page.onDOMContentLoaded.apply(this, value1));
};
// handler has access to value1 and valueString
page.onDOMContentLoaded = function(event) {
value1.current = true;
value1.timeStamp = Date.now();
valueString="goodbye";
console.log('**** DOM CONTENT LOADED ****');
};
page.onResourceReceived = function (res) {
console.log('received ' + res.id + ' ' + res.stage);
};
page.onError = function (msg, trace) {
console.log(msg);
trace.forEach(function(item) {
//console.log(' ', item.file, ':', item.line);
});
};
page.open(address, function (status) {
console.log("page opened");
if (status !== 'success') {
console.log('FAIL to load the address');
}
console.log("value = " + JSON.stringify(value1));
console.log("valueString=" + valueString);
phantom.exit();
});
}
使用代码,valueString是&#39;再见&#39;即使它没有通过&#39; .apply(this,value1)&#39;
传入输出显示
netlog.js
received 1 start
received 1 end
received 2 end
received 3 start
received 3 end
**** DOM CONTENT LOADED ****
received 5 start
received 5 end
received 6 start
received 6 end
received 7 start
received 9 start
received 8 start
received 7 end
received 9 end
received 8 end
received 4 start
received 4 end
page opened
value = {"current":true,"timeStamp":1473693805039}
valueString=goodbye
**** DOM CONTENT LOADED ****
**** DOM CONTENT LOADED ****
valueString变量设置在右侧url收到的id为3并且它粘在一起,以便我可以在page.open中看到它。
为什么&#39; **** DOM内容加载****&#39;在page.open之后打印?
但是如果我将page.onInitialized更改为以下内容而没有apply,则不会设置value1或valueString。
page.onInitialized = function() {
// add handler & apply value1 to handler's scope'
page.evaluate(function(domContentLoaded) {
document.addEventListener('DOMContentLoaded', domContentLoaded, false);
}, page.onDOMContentLoaded);
};
为什么我需要使用apply方法来获取在处理程序中设置的全局变量?
为什么我只需将value1传递给apply即可设置valueString?
答案 0 :(得分:1)
page.evaluate
是PhantomJS中页面上下文的大门。只能传入原始对象。来自docs:
注意:
evaluate
函数的参数和返回值必须 是一个简单的原始对象。经验法则:如果可以的话 通过JSON序列化,然后就可以了。闭包,函数,DOM节点等将不工作!
因此,page.onDOMContentLoaded
是一个函数,不能传递给页面上下文。你必须传递和反对页面上下文并在那里定义一个函数。
您可以使用类似的内容(使用the onCallback
& callPhantom
pair):
page.onCallback = function(data){
if (data.type == 'DOMContentLoaded') {
console.log('outer: DOMContentLoaded');
}
};
page.onInitialized = function() {
page.evaluate(function(value1) {
// TODO: do something with value1
document.addEventListener('DOMContentLoaded', function(){
console.log('inner: DOMContentLoaded');
window.callPhantom({ type: 'DOMContentLoaded' });
}, false);
}, value1);
};
为什么'**** DOM CONTENT LOADED ****'打印在page.open后?
请记住,Function.prototype.apply
会立即执行一项功能。在这种情况下,它是page.onDOMContentLoaded
内的page.onInitialized
函数。因此,无论何时页面“初始化”,您都会看到执行page.onDOMContentLoaded
。
为什么在执行停止后初始化两个页面是一个完全不同的问题。这可能只是PhantomJS的一些特点。
答案 1 :(得分:0)
基于Artjom B.答案,这是工作代码:
"use strict";
console.log("netlog.js");
var page = require('webpage').create(),
system = require('system'),
address;
var valueString = "hello";
var value1 = {
current: false,
timeStamp: null
};
if (system.args.length === 1) {
//console.log('Usage: phantomjs netlog.js <some URL>');
phantom.exit(1);
} else {
var PHANTOM_FUNCTION_PREFIX = '/* PHANTOM_FUNCTION */';
address = system.args[1];
page.onConsoleMessage = function(msg) {
if (msg.indexOf(PHANTOM_FUNCTION_PREFIX) === 0) {
eval('(' + msg + ')()');
} else {
console.log(msg);
}
};
page.onCallback = function(data){
if (data.type == 'DOMContentLoaded') {
value1.current = true;
value1.timeStamp = Date.now();
valueString = "goodbye";
console.log('outer: DOMContentLoaded');
}
};
page.onInitialized = function() {
page.evaluate(function() {
document.addEventListener('DOMContentLoaded', function(){
console.log('inner: DOMContentLoaded');
window.callPhantom({ type: 'DOMContentLoaded' });
}, false);
});
};
page.onResourceReceived = function (res) {
console.log('received ' + res.id + ' ' + res.stage);
};
page.onError = function (msg, trace) {
console.log(msg);
trace.forEach(function(item) {
//console.log(' ', item.file, ':', item.line);
});
};
page.open(address, function (status) {
console.log("page opened");
if (status !== 'success') {
console.log('FAIL to load the address');
}
console.log("value = " + JSON.stringify(value1));
console.log("valueString=" + valueString);
phantom.exit();
});
}
此代码允许onDOMContentLoaded事件处理程序设置事件的时间戳 - 这是一个全局变量。