JavaScript - CS193H: High Performance Web Sites

advertisement
JavaScript: The Good Parts
Part Six: Ajax Performance
Douglas Crockford
douglas@crockford.com
Memento
The Sessionless Web
• Cookies for pseudosessions.
• Cookies enable CSRF attacks.
• Every action results in a page
replacement.
• Pages are heavy, complicated, multipart
things.
• The web is a big step backwards in
individual productivity.
“When your only tool is a
hammer, every problem looks
like a webpage.”
The Ajax Revolution
The page is an application with a
data connection to a server.
When the user does something,
we send a JSON message to the
server, and receive a JSON
message as the result.
A JSON message is less work
for the server to generate,
moves faster on the wire, and
is less work for the browser to
parse and render
than an HTML document.
Division of Labor
How is the application divided
between the browser and the
server?
Pendulum of Despair
Server
The browser is a terminal.
Pendulum of Despair
Server
Browser
The browser is a terminal
The server is a file system.
Seek the Middle Way.
A pleasant dialogue between
specialized peers.
Ajaxify
• The client and server are in a dialog.
• Make the messages between them as
small as possible.
• The client does not need a copy of the
database. It just needs, at any moment,
just enough information to serve the user.
• Don't rewrite the server application in
JavaScript!
The Poor Browser
• The browser is a very inefficient
application platform.
• If your application becomes bloated,
performance will be very bad.
• Try to keep the client programming light.
Amazingly, the browser works
• But it doesn't work well.
• It is a difficult platform to work with.
• There are significant security problems.
• There are significant performance
problems.
• It was not designed to be an application
delivery system.
• Ajax pushes the browser really hard.
Correctness First
• Do not worry about optimization until you
have the application working correctly.
• If it isn’t right, it doesn’t matter that if it is
fast.
• Test for performance early.
• Test in customer configurations: Slow
networks, slow computers.
• Internal networks and developer-class machines
can mask performance problems.
Premature optimization is the root
of all evil. — Donald Knuth
• Use YSlow to reduce startup time.
• Don't optimize until you need to, but find out as
early as possible if you need to.
• Clean, correct code is easier to optimize.
• Tweaking is usually ineffective.
• Sometimes restructuring or redesign is
required.
Example
var fibonacci = function (n) {
return n < 2 ? n :
fibonacci(n - 1) +
fibonacci(n - 2);
};
• fibonacci(40)
• Calls itself 331,160,280 times.
Memoizer
var memoizer = function (memo, fundamental) {
var shell = function (n) {
var result = memo[n];
if (typeof result !== 'number') {
result = fundamental(shell, n);
memo[n] = result;
}
return result;
};
return shell;
};
Memoizer
var fibonacci =
memoizer([0, 1], function (recur, n) {
return recur(n - 1) + recur(n - 2);
});
• fibonacci(40)
• Calls itself 38 times.
• The key to optimization is work avoidance.
Code Quality
• High quality code is mostly likely to avoid
platform problems.
• Code Conventions for the JavaScript
Programming Language
• http://javascript.crockford.com/code.html
• Use JSLint.com. Pass with no warnings.
Have regular code readings.
• Don’t wait until release to do code reviews.
• Do team code reading regularly during
development.
• Experienced developers can lead by
example.
• Novice developers learn from the group.
• Problems can be discovered early.
• Good techniques can be shared early.
Two Kinds of Optimization
• Streamlining
Algorithm replacement
Work avoidance
Code removal
These things are always good to do
• Special Casing
Adds cruft, increases code size
Should only be done when proven necessary
Avoid unnecessary displays or
animation.
• Everything costs.
• Wow costs.
• As the number of widgets on the page
increases, overall ongoing performance gets
worse.
Only speed up things that take
a lot of time.
Speeding up things that take very
little time will yield very little
improvement.
Only speed up things that take a lot
of time.
• If profiling shows that you are spending
most of your time in A, don't bother
optimizing C.
A
B
C
D
Improving performance
• If JavaScript were infinitely fast, most
pages would run at about the same speed.
• The bottleneck tends to be the DOM
interface.
• There is a significant cost every time you
touch the DOM tree.
• Each touch can result in a reflow
computation, which is expensive.
Touch lightly
• It is faster to manipulate new nodes before
they are attached to the tree.
• Touching unattached nodes avoids the
reflow cost.
• Setting innerHTML does an enormous
amount of work, but browsers are really
good at it, and it only touches the DOM
once.
Make good use of Ajax
Libraries
Effective code reuse will make
widgets more effective.
How IE8 Spends Its Time
Other 2.5%
JScript 3.23%
Format 8.66%
DOM 5.05%
Rendering 27.25%
Marshalling 7.34%
Layout 43.16%
HTML 2.81%
• Average time allocation of the Alexa 100:
DOM 12.47%
Marshalling 7.85%
HTML 1.57%
Rendering 9.21%
Layout 9.41%
Format 38.97%
Other 3.72%
JScript 14.43%
How IE8 Spends Its Time
• Opening a thread in GMail:
Coding Efficiency
• Common subexpression removal.
• Loop invariant removal.
• Most compilers in most programming
languages do these optimizations for you.
• But not JavaScript.
Before
var i;
for (i = 0; i < divs.length; i += 1) {
divs[i].style.color = "black";
divs[i].style.border = thickness +
'px solid blue';
divs[i].style.backgroundColor = "white";
}
After
var border = thickness + 'px solid blue',
nrDivs = divs.length,
ds, i;
for (i = 0; i < nrDivs; i += 1) {
ds = divs[i].style;
ds.color = "black";
ds.border = border;
ds.backgroundColor = "white";
}
Strings
• Concatenation with +
Each operation allocates memory
foo = a + b;
• Concatenate with array.join('')
The contents of an array are concatenated
into a single string
foo = [a, b].join('');
Don't Tune For Quirks
• Some browsers have surprising
inefficiencies.
• A trick that is faster on Browser A might be
slower on Browser B.
• The performance characteristics of the
next generation may be significantly
different.
• Avoid short-term optimizations.
Don't Optimize Without Measuring
• Intuitions are often wrong.
start_time = new Date().valueOf();
code_to_measured();
end_time = new Date().valueOf();
elapsed_time = end_time - start_time;
• A single trial is unreliable. Timers can be
off by as much as 15 msec.
• Even accurate measurements can lead to
wrong conclusions.
O (1)
• An operation that is performed only once
is not worth optimizing.
O (n)
Time
• An operation that is performed many times
may be worth optimizing.
Slope: Time per Iteration
Fixed time: Startup and cleanup
n
The Axis of Error
Time
• Inefficiency
Inefficiency
n
The Axis of Error
• Frustration
Time
Frustration
n
The Axis of Error
• Failure
Time
Failure
n
Time
O (n)
Slope: Time per Iteration
Fixed time: Startup and cleanup
n
Time
O (n log n)
n
O (n2)
Time
Generally not suitable for browser applications
except when n is very small.
n
The most effective way to make
programs faster is to make n
smaller.
Ajax allows for just-in-time
data delivery.
The Wall.
Download