1. Trang chủ
  2. » Công Nghệ Thông Tin

Phát triển Javascript - part 10 pps

10 276 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 2,39 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Listing 4.7 YUI Test HTML fixture file Relative performance of loops Relative performance of loops All the tests do the exact same thing: loop over all items in the array and ac

Trang 1

// Run tests

runBenchmark("for-loop",

forLoop);

runBenchmark("for-loop, cached length",

forLoopCachedLength);

runBenchmark("for-loop, direct array access",

forLoopDirectAccess);

runBenchmark("while-loop",

whileLoop);

runBenchmark("while-loop, cached length property",

whileLoopCachedLength);

runBenchmark("reversed while-loop",

reversedWhileLoop);

runBenchmark("double reversed while-loop",

doubleReversedWhileLoop);

The setTimeout call is important to avoid choking the browser while testing

The browser uses a single thread to run JavaScript, fire events and render web pages,

and the timers allow the browser some “breathing room” to pick up on queued tasks

between tests that are potentially long running Breaking the workload up with

timers also avoids browsers interrupting the tests to warn us about “slow scripts.”

To run these benchmarks, all we need is a simple HTML file, like the one in

Listing 4.7, that loads the script Save the file in benchmarks/loops.html

Listing 4.7 YUI Test HTML fixture file

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"

"http://www.w3.org/TR/html4/strict.dtd">

<html>

<head>

<title>Relative performance of loops</title>

<meta http-equiv="content-type"

content="text/html; charset=UTF-8">

</head>

<body>

<h1>Relative performance of loops</h1>

<script type="text/javascript" src=" /lib/benchmark.js">

</script>

<script type="text/javascript" src="loops.js"></script>

</body>

</html>

All the tests do the exact same thing: loop over all items in the array and access

the current item Accessing the current item adds to the footprint of the test, but

it also allows us to compare the loop that accesses the current item in the loop

Download from www.eBookTM.com

Trang 2

conditional with the rest This is not always a safe choice, because empty strings,

null, 0, and other false values will terminate the loop Also, this style of looping

performs terribly on some browsers and should be avoided Because all the tests

access the current item, we can disregard the overhead as fluctuations in the test

results will be the result of the different looping styles Note that the reversed

while-loopis not directly comparable as it loops the array backwards However,

whenever order is not important, it’s commonly the fastest way to loop an array, as

seen by running the above benchmark

Benchmarks such as that in Listing 4.6 are dead easy to set up Still, to make them

easier to integrate into our workflow, we can craft a simple benchmark function

that removes all unnecessary cruft from writing benchmarks Listing 4.8 shows one

possible such function The function accepts a label for the series of tests and then

an object where the property names are taken as test names and property values are

run as tests The last argument is optional and instructs benchmark as to how many

times a test should be run Results are printed in both full and average time per test

Listing 4.8 A simple benchmarking tool

var benchmark = (function () {

function init(name) {

var heading = document.createElement("h2");

heading.innerHTML = name;

document.body.appendChild(heading);

var ol = document.createElement("ol");

document.body.appendChild(ol);

return ol;

}

function runTests(tests, view, iterations) {

for (var label in tests) {

if (!tests.hasOwnProperty(label) ||

typeof tests[label] != "function") {

continue;

}

(function (name, test) {

setTimeout(function () {

var start = new Date().getTime();

var l = iterations;

while (l ) {

test();

} Download from www.eBookTM.com

Trang 3

var total = new Date().getTime() - start;

var li = document.createElement("li");

li.innerHTML = name + ": " + total +

"ms (total), " + (total / iterations) +

"ms (avg)";

view.appendChild(li);

}, 15);

}(label, tests[label]));

}

}

function benchmark(name, tests, iterations) {

iterations = iterations || 1000;

var view = init(name);

runTests(tests, view, iterations);

}

return benchmark;

}());

The benchmark function does one thing noticeably different from our

previ-ous example It runs each iteration as a function The test is captured as a function,

which is run the specified number of times This function call itself has a footprint,

so the end result is less accurate as to how long the test took, especially for small

test functions However, in most cases the overhead is ignorable because we are

testing relative performance To avoid having the function call skew tests too much,

we can write the tests so that they are sufficiently complex An alternative way to

implement this is to take advantage of the fact that functions have a length

prop-erty that reveals how many formal parameters a function takes If this number is

zero, then we loop Otherwise, we will assume that the test expects the number of

iterations as an argument and simply call the function, passing the iteration count

This can be seen in Listing 4.9

Listing 4.9 Using Function.prototype.length to loop or not

// Inside runTests

(function (name, test) {

setTimeout(function () {

var start = new Date().getTime();

var l = iterations;

if (!test.length) {

while (l ) {

Download from www.eBookTM.com

Trang 4

test();

}

} else {

test(l);

}

var total = new Date().getTime() - start;

var li = document.createElement("li");

li.innerHTML = name + ": " + total +

"ms (total), " + (total / iterations) +

"ms (avg)";

view.appendChild(li);

}, 15);

}(label, tests[label]));

As an example of benchmark’s usage, we can reformat the loop tests using it

In this example, the length of the array to loop is somewhat reduced, and the total

number of iterations is increased Listing 4.10 shows the rewritten test Some of the

tests have been removed for brevity

Listing 4.10 Using benchmark

var loopLength = 100000;

var array = [];

for (var i = 0; i < loopLength; i++) {

array[i] = "item" + i;

}

benchmark("Loop performance", {

"for-loop": function () {

for (var i = 0, item; i < array.length; i++) {

item = array[i];

}

},

"for-loop, cached length": function () {

for (var i = 0, l = array.length, item; i < l; i++) {

item = array[i];

}

},

//

"double reversed while-loop": function () {

Download from www.eBookTM.com

Trang 5

var l = array.length, i = l, item;

while (i ) {

item = array[l - i - 1];

}

}

}, 1000);

This sort of benchmarking utility can be extended to yield more helpful reports

Highlighting the fastest and slowest tests comes to mind as a useful extension Listing

4.11 shows a possible solution

Listing 4.11 Measuring and highlighting extremes

// Record times

var times;

function runTests (tests, view, iterations) {

//

(function (name, test) {

//

var total = new Date().getTime() - start;

times[name] = total;

//

}(label, tests[label]));

//

}

function highlightExtremes(view) {

// The timeout is queued after all other timers, ensuring

// that all tests are finished running and the times

// object is populated

setTimeout(function () {

var min = new Date().getTime();

var max = 0;

var fastest, slowest;

for (var label in times) {

if (!times.hasOwnProperty(label)) {

continue;

}

if (times[label] < min) {

min = times[label];

fastest = label;

}

Download from www.eBookTM.com

Trang 6

if (times[label] > max) {

max = times[label];

slowest = label;

}

}

var lis = view.getElementsByTagName("li");

var fastRegexp = new RegExp("^" + fastest + ":");

var slowRegexp = new RegExp("^" + slowest + ":");

for (var i = 0, l = lis.length; i < l; i++) {

if (slowRegexp.test(lis[i].innerHTML)) {

lis[i].style.color = "#c00";

}

if (fastRegexp.test(lis[i].innerHTML)) {

lis[i].style.color = "#0c0";

}

}

}, 15);

}

// Updated benchmark function

function benchmark (name, tests, iterations) {

iterations = iterations || 1000;

times = {};

var view = init(name);

runTests(tests, view, iterations);

highlightExtremes(view);

}

To further enhance benchmark we could decouple the DOM manipulation

that displays results to allow for alternate report generators This would also allow us

to benchmark code in environments without a DOM, such as server-side JavaScript

runtimes

4.2.2 Profiling and Locating Bottlenecks

Firebug, the web developer add-on for Firefox, offers a profiler that can profile

code as it runs For instance, we can launch a live site, start the profiler and click a

link that triggers a script After the script finishes we stop the profiler At this point

the profile report will show us a breakdown of all functions run, along with how

much time was spent on each of them Many times the number of functions run

to perform some task can in itself be valuable information that points us to overly

Download from www.eBookTM.com

Trang 7

Figure 4.1 Profiling Twitter’s search feature.

complex code As an example of the Firebug profiler, Figure 4.1 shows the profile

report after having used Twitter’s search feature, which uses an XMLHttpRequest

to fetch data, and manipulates the DOM to display the results The profile report

shows a lot going on inside jQuery, and a total of over 31,000 function calls

4.3 Summary

In this chapter we have seen how unit tests can be utilized not necessarily only to

support production code, but also to help us learn more about JavaScript Keeping

a suite of learning tests is a great way to document our learning, and they provide

a handy reference over issues we have encountered in the past While reading this

book I encourage you to try out some of the examples and play with them to

understand what is going on If you don’t already have a learning test suite, now

would be a great time to start one, and you can start writing tests to further your

understanding of examples from this book

Benchmarks can help guide decisions when there are several viable ways of

solving a given problem By measuring relative performance we can learn patterns

Download from www.eBookTM.com

Trang 8

that tend to perform better, and keeping benchmarks along with learning tests makes

for a powerful personal knowledge bank

This chapter concludes the introduction to automated testing In Part II,

JavaScript for Programmers, we will take a deep dive into JavaScript, specifically

focusing on aspects of the language that sets it apart from other programming

lan-guages This means a detailed look at objects, constructors, and prototypes, as well

as JavaScript scoping and functions

Download from www.eBookTM.com

Trang 9

Part II

JavaScript for

Programmers

Download from www.eBookTM.com

Trang 10

Download from www.eBookTM.com

Ngày đăng: 04/07/2014, 22:20

TỪ KHÓA LIÊN QUAN