foo();
bar();
baz();
function foo() {...}
function bar() {...}
function baz() {...}
要度量其运行时间:
var start,
time = 0;
timer = performance ? performance.now : Date.now;
// start timer
start = timer();
foo();
bar();
baz();
// stop timer
time = timer() - start;
// log time in ms
console.log(Math.floor(time*100) / 100 + 'ms');
然而,如果这些函数是异步执行的函数呢?那么下列的时间度量代码,计算出来的duration就不准确了:
function doSomething() {
console.log('Async task');
}
// start timer
start = timer();
foo();
setTimeout(doSomething, 2000);
bar();
baz();
// stop timer
time = timer() - start;
什么是Angular的zone?
Zones can perform an operation - such as starting or stopping a timer, or saving a stack trace - each time that code enters or exits a zone. They can override methods within our code, or even associate data with individual zones.
zone可以在一段代码进入或者离开一个zone的时候,执行一个操作,比如开启或者关闭计时器,或者保存一个堆栈跟踪。
Zones are actually a language feature in Dart.
Zone实际上是编程语言Dart的一个特性。Dart编译之后的代码也是JavaScript,所以我们可以直接在JavaScript里实现Zone的特性。
Angular项目里通常都有zone.js的依赖:
function main() {
foo();
setTimeout(doSomething, 2000);
bar();
baz();
}
zone.run(main);
Zones can perform an operation each time our code enters or exits a zone.
var myZoneSpec = {
beforeTask: function () {
console.log('Before task');
},
afterTask: function () {
console.log('After task');
}
};
var myZone = zone.fork(myZoneSpec);
myZone.run(main);
// Logs:
// Before task
// After task
// Before task
// Async task
// After task
It turns out that there are a few other hooks. In fact, those aren’t just hooks, but monkey-patched methods on the global scope.
全局scope里还存在称为monke-patched的方法。
when we call setTimeout() we actually call Zone.setTimeout(), which in turn creates a new zone using zone.fork() in which the given handler is executed.
当我们调用setTimeout时,我们实际上调用的是Zone.setTimeout, 后者会使用zone.fork(),创建新的zone,而setTimeout里的函数,就运行在这个新fork出来的zone里面。
And that’s why our hooks are executed as well, because the forked zone in which the handler will be executed, simply inherits from the parent zone.
而hook执行两次的原因,是因为函数运行于fork出来的zone里面,而后者继承了parent zone的hook.
Zone.js重载了下列方法,并且以hook的方式提供给应用开发人员使用:
Zone.setInterval()
Zone.alert()
Zone.prompt()
Zone.requestAnimationFrame()
Zone.addEventListener()
Zone.removeEventListener()
We might wonder why methods like alert() and prompt() are patched as well. As mentioned earlier, those patched methods are hooks at the same time. We can change and extend them by forking a zone exactly the same way we did with beforeTask and afterTask. This turns out to be super powerful, because we can intercept calls to alert() and prompt() and change their behaviour when we write tests.
类似alert和prompt方法和其他方法一样同时被patch,在fork一个新zone时,可以传入我们自己的实现进去,在写单元测试代码时尤其有用。
用于度量一段异步执行代码执行时间的profilingZone的实现源代码: