Stay up to date with the latest marketing, sales and service tips and news.
原文链接:Kent Hansen - Faking a web browser environment in QtScript
下面这个问题最近在qt-interest邮件列表中经常被问到:我如何才能在QtScript中调试运行[一些任意的]JavaScript代码(通常是包含在一个网页中的)呢?这是一个有趣的题目,我忍不住在这里回答一下。
短答案:您不能。
长答案:这取决于这段脚本在做什么——更精确地,这个脚本使用了哪些JavaScript API。试着使用QScriptEngine::evaluate()来调试运行这段脚本,并且看看是否会得到一个ReferenceError;如果没有,那么你就完成了!但是JavaScript代码通常会被期望运行在一个完整的JavaScript环境中。这个环境是ECMA-262标准环境的一个超集,而QtScript在这一点上完成地很好。JavaScript脚本会期待DOM API的存在。脚本还会期待window
对象和document
对象的存在。脚本也许会检查window.navigator.userAgent
来试图决定一些常用属性的呈现(尽管这一点非常无用)。诸如此类。如果缺少了其中的一部分,那么在一个通常的QScriptEngine中调试运行JavaScript代码就会得到一个参考错误,错误信息类似与:"Can't find variable: window"
。该做些什么呢?
我们可以试图伪造一个环境。这个思路就是只实现所需的JavaScript API,然后我们想运行的这些脚本就可以运行了。这其实也就是QtScript的Context2D实例所做的。另外HTML5 Canvas API中的绝大部分,就是实现了DOM API(包括基本的事件处理——在这里特别感谢Zack写出了这么酷的实例)的一个子集,因此网上绝大多数脚本就都可以在不修改的情况下运行了。
这个伪造的/部分的环境既可以通过QtScript代码实现,也可以通过本地对象(QObject和/或函数指针)实现;这取决于您的使用案例。但通常情况下,过程如下:
为了演示上述方案,让我们来考虑一个真实的使用案例。es5conform是一个ECMA-262一致性套件;它可以检查一个ECMA-262实现与标准的一致性如何。如果您下载这个测试套件,您将会注意到所提供的测试运行器是一个网页(runtests.html
)。让我们使它运行在QtScript中。这是完全可能的,因为这些测试本身只是JavaScript中ECMA-262的一部分。并且测试结果可以体现有关QtScript一致性水平的有价值信息。
这里是runtests.html
的一些基础部分:
<script type="text/javascript" src="SimpleTestHarness/sth.js"></script>
<script>
var ES5Harness = activeSth;
</script>
...
<script type="text/javascript" src="TestCases/chapter11/11.4/11.4.1/11.4.1-3-3.js"></script>
<script type="text/javascript" src="TestCases/chapter11/11.4/11.4.1/11.4.1-4.a-1.js"></script>
<script type="text/javascript" src="TestCases/chapter11/11.4/11.4.1/11.4.1-4.a-10.js"></script>
...
<script>
ES5Harness.startTesting();
</script>
打开SimpleTestHarness/sth.js
并且研究一下,那么很显然它是一个用于注册并且运行测试的小库。测试本身被存储在不同的.js文件中(在TestCases/
下)。所以工作计划就是使得es5conform可以在QtScript中运行,具体如下:
SimpleTestHarness/sth.js
。activeSth
赋给全局变量ES5Harness
。TestCases/
下的一个或者多个.js文件。ES5Harness.startTesting()
函数。上面的步骤可以通过QtScript Shell应用程序(Qt中的examples/script/qscript
)实现,它只是一个基本的QScriptEngine::evaluate()
的单机封装,您可以把脚本传给它。试一下第一步:
qscript SimpleTestHarness/sth.js
ReferenceError: Can't find variable: window
<anonymous>()@SimpleTestHarness/sth.js:295
结果就是这段脚本使用了全局的window
变量来获得这个全局对象的参考。我们创建一个包含如下内容的pre.js
文件:
window = this;
当上述语句在全局代码中被调试运行时,this
将会是这个全局对象的一个参考。我们再次运行qscript,但是把pre.js
放在sth.js
之前:
qscript pre.js SimpleTestHarness/sth.js
ReferenceError: Can't find variable: document
<anonymous>()@SimpleTestHarness/sth.js:259
好的,一个新错误。有问题的脚本代码行是
this.resultsDiv = document.createElement("div");
让我们添加一个伪造的document
对象到pre.js
中:
document = {
createElement: function(tagName) {
return { nodeName: tagName };
}
};
在经过几次迭代之后,sth.js
将会被成功调试运行。现在创建一个post.js
文件:
ES5Harness = activeSth;
和run.js
:
ES5Harness.startTesting();
最后,我们可以运行一个实际的测试:
qscript pre.js SimpleTestHarness/sth.js post.js TestCases/chapter11/11.4/11.4.1/11.4.1-0-1.js run.js
没有错误,但也没有输出!
看一看sth.js
中有关测试结果报告的代码,输出是使用如下定义的println()
函数生成的:
sth.prototype.println = function (s) {
this.innerHTML += s;
this.innerHTML += "<BR/>";
}
再一次的,网页导向的。我们可以使用QtScript Shell内置的print()
函数来替换它(例如在post.js
中),或者在测试结束之后把ES5Harness
对象的innerHTML
属性输出出来。第三个选项是把innerHTML
定义为一个getter/setter属性(像一个Qt/C++属性一样),所以只要这个属性被赋值的时候,setter函数就会被调用了。
一个更加灵活的方案是完全地忽略HTML输出并且自己处理测试结果的内部呈现;在这种方式下,我们可以获得对输出格式的完全控制。看一看sth.prototype.report()
函数,我们知道了如何访问每一个测试记录的描述和结果属性。举个例子,把它们放在一起,es5conform就可以很容易地被集成到Qt的自动测试系统中(我们所完成的Qt和Mozilla以及V8的测试套件一部分,是用类似方式工作的)。
现在我们可以把es5conform封装到一个使用QScriptEngine::evaluate()
以及其它相关函数的Qt应用程序中,这样就可以做任何事情了,这样也就移除了对QtScript Shell应用程序的依赖。如果您需要或者想用本地代码实现任意API,这么做也是必需的。
在QtScript中调试运行任意的JavaScript代码的原则很简单:发现脚本是如何工作的,并且实现(“伪造”)所需的JavaScript API。这个技术也适用于把JavaScript导入到QML中;创建带有ID以及与JavaScript可访问属性匹配的属性的元素。关于后面情况的一个实例,请看看QTBUG-8576(很棒的缺陷报告!)中所附的qmlfbench.tar.gz
。
下一步,看看类似于prototype.js(使得在QtScript/QML中使用Class.create()
以及其它成为可能)的“伪造的”环境。这还需要一些DOM API,但是看起来是可行的。
Stay up to date with the latest marketing, sales and service tips and news.
Download the latest release here: www.qt.io/download.
Qt 6 was created to be the productivity platform for the future, with next-gen 2D & 3D UX and limitless scalability.
Find webinars, use cases, tutorials, videos & more at resources.qt.io
Check out all our open positions here and follow us on Instagram to see what it's like to be #QtPeople.
Näytä tämä julkaisu Instagramissa.Henkilön Qt (@theqtcompany) jakama julkaisu
Qt Group includes The Qt Company Oy and its global subsidiaries and affiliates.