SlideShare a Scribd company logo
Visit https://ebookultra.com to download the full version and
explore more ebooks
High Performance JavaScript Build Faster Web
Application Interfaces 1st Edition Nicholas C.
Zakas
_____ Click the link below to download _____
https://ebookultra.com/download/high-performance-
javascript-build-faster-web-application-interfaces-1st-
edition-nicholas-c-zakas/
Explore and download more ebooks at ebookultra.com
Here are some suggested products you might be interested in.
Click the link to download
Professional JavaScript for Web Developers 3rd Edition
Nicholas C. Zakas
https://ebookultra.com/download/professional-javascript-for-web-
developers-3rd-edition-nicholas-c-zakas/
Professional JavaScript for web developers 2nd ed Edition
Nicholas C. Zakas
https://ebookultra.com/download/professional-javascript-for-web-
developers-2nd-ed-edition-nicholas-c-zakas/
Learning Julia Build high performance applications for
scientific computing 1st Edition Anshul Joshi
https://ebookultra.com/download/learning-julia-build-high-performance-
applications-for-scientific-computing-1st-edition-anshul-joshi/
Simulation Engineering Build Better Embedded Systems
Faster 1st Edition Jim Ledin (Author)
https://ebookultra.com/download/simulation-engineering-build-better-
embedded-systems-faster-1st-edition-jim-ledin-author/
Web Application Firewalls 1st Edition Chad Russell
https://ebookultra.com/download/web-application-firewalls-1st-edition-
chad-russell/
SproutCore Web Application Development 1st Edition Keating
https://ebookultra.com/download/sproutcore-web-application-
development-1st-edition-keating/
Web Application Defender s Cookbook Battling Hackers and
Protecting Users 1st Edition Ryan C. Barnett
https://ebookultra.com/download/web-application-defender-s-cookbook-
battling-hackers-and-protecting-users-1st-edition-ryan-c-barnett/
Julia High performance 1st Edition Avik Sengupta
https://ebookultra.com/download/julia-high-performance-1st-edition-
avik-sengupta/
High Performance Plastics 2011 1st Edition Ismithers
https://ebookultra.com/download/high-performance-plastics-2011-1st-
edition-ismithers/
High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas
High Performance JavaScript Build Faster Web
Application Interfaces 1st Edition Nicholas C. Zakas
Digital Instant Download
Author(s): Nicholas C. Zakas
ISBN(s): 9780596802790, 059680279X
Edition: 1
File Details: PDF, 4.35 MB
Year: 2010
Language: english
High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas
High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas
High Performance JavaScript
High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas
High Performance JavaScript
Nicholas C. Zakas
Beijing • Cambridge • Farnham • Köln • Sebastopol • Taipei • Tokyo
High Performance JavaScript
by Nicholas C. Zakas
Copyright © 2010 Yahoo!, Inc. All rights reserved.
Printed in the United States of America.
Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions
are also available for most titles (http://my.safaribooksonline.com). For more information, contact our
corporate/institutional sales department: (800) 998-9938 or corporate@oreilly.com.
Editor: Mary E. Treseler
Production Editor: Adam Zaremba
Copyeditor: Genevieve d’Entremont
Proofreader: Adam Zaremba
Indexer: Fred Brown
Cover Designer: Karen Montgomery
Interior Designer: David Futato
Illustrator: Robert Romano
Printing History:
March 2010: First Edition.
Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of
O’Reilly Media, Inc. High Performance JavaScript, the image of a short-eared owl, and related trade dress
are trademarks of O’Reilly Media, Inc.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as
trademarks. Where those designations appear in this book, and O’Reilly Media, Inc. was aware of a
trademark claim, the designations have been printed in caps or initial caps.
While every precaution has been taken in the preparation of this book, the publisher and author assume
no responsibility for errors or omissions, or for damages resulting from the use of the information con-
tained herein.
TM
This book uses RepKover™, a durable and flexible lay-flat binding.
ISBN: 978-0-596-80279-0
[M]
1268245906
This book is dedicated to my family, Mom, Dad,
and Greg, whose love and support have kept me
going through the years.
High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas
Table of Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
1. Loading and Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Script Positioning 2
Grouping Scripts 4
Nonblocking Scripts 5
Deferred Scripts 5
Dynamic Script Elements 6
XMLHttpRequest Script Injection 9
Recommended Nonblocking Pattern 10
Summary 14
2. Data Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Managing Scope 16
Scope Chains and Identifier Resolution 16
Identifier Resolution Performance 19
Scope Chain Augmentation 21
Dynamic Scopes 24
Closures, Scope, and Memory 24
Object Members 27
Prototypes 27
Prototype Chains 29
Nested Members 30
Caching Object Member Values 31
Summary 33
3. DOM Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
DOM in the Browser World 35
Inherently Slow 36
DOM Access and Modification 36
innerHTML Versus DOM methods 37
vii
Cloning Nodes 41
HTML Collections 42
Walking the DOM 46
Repaints and Reflows 50
When Does a Reflow Happen? 51
Queuing and Flushing Render Tree Changes 51
Minimizing Repaints and Reflows 52
Caching Layout Information 56
Take Elements Out of the Flow for Animations 56
IE and :hover 57
Event Delegation 57
Summary 59
4. Algorithms and Flow Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Loops 61
Types of Loops 61
Loop Performance 63
Function-Based Iteration 67
Conditionals 68
if-else Versus switch 68
Optimizing if-else 70
Lookup Tables 72
Recursion 73
Call Stack Limits 74
Recursion Patterns 75
Iteration 76
Memoization 77
Summary 79
5. Strings and Regular Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
String Concatenation 81
Plus (+) and Plus-Equals (+=) Operators 82
Array Joining 84
String.prototype.concat 86
Regular Expression Optimization 87
How Regular Expressions Work 88
Understanding Backtracking 89
Runaway Backtracking 91
A Note on Benchmarking 96
More Ways to Improve Regular Expression Efficiency 96
When Not to Use Regular Expressions 99
String Trimming 99
Trimming with Regular Expressions 99
viii | Table of Contents
Trimming Without Regular Expressions 102
A Hybrid Solution 103
Summary 104
6. Responsive Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
The Browser UI Thread 107
Browser Limits 109
How Long Is Too Long? 110
Yielding with Timers 111
Timer Basics 112
Timer Precision 114
Array Processing with Timers 114
Splitting Up Tasks 116
Timed Code 118
Timers and Performance 119
Web Workers 120
Worker Environment 120
Worker Communication 121
Loading External Files 122
Practical Uses 122
Summary 124
7. Ajax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Data Transmission 125
Requesting Data 125
Sending Data 131
Data Formats 134
XML 134
JSON 137
HTML 141
Custom Formatting 142
Data Format Conclusions 144
Ajax Performance Guidelines 145
Cache Data 145
Know the Limitations of Your Ajax Library 148
Summary 149
8. Programming Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Avoid Double Evaluation 151
Use Object/Array Literals 153
Don’t Repeat Work 154
Lazy Loading 154
Conditional Advance Loading 156
Table of Contents | ix
Use the Fast Parts 156
Bitwise Operators 156
Native Methods 159
Summary 161
9. Building and Deploying High-Performance JavaScript Applications . . . . . . . . . . . 163
Apache Ant 163
Combining JavaScript Files 165
Preprocessing JavaScript Files 166
JavaScript Minification 168
Buildtime Versus Runtime Build Processes 170
JavaScript Compression 170
Caching JavaScript Files 171
Working Around Caching Issues 172
Using a Content Delivery Network 173
Deploying JavaScript Resources 173
Agile JavaScript Build Process 174
Summary 175
10. Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
JavaScript Profiling 178
YUI Profiler 179
Anonymous Functions 182
Firebug 183
Console Panel Profiler 183
Console API 184
Net Panel 185
Internet Explorer Developer Tools 186
Safari Web Inspector 188
Profiles Panel 189
Resources Panel 191
Chrome Developer Tools 192
Script Blocking 193
Page Speed 194
Fiddler 196
YSlow 198
dynaTrace Ajax Edition 199
Summary 202
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
x | Table of Contents
Preface
When JavaScript was first introduced as part of Netscape Navigator in 1996, perform-
ance wasn’t that important. The Internet was in its infancy and it was, in all ways, slow.
From dial-up connections to underpowered home computers, surfing the Web was
more often a lesson in patience than anything else. Users expected to wait for web pages
to load, and when the page successfully loaded, it was a cause for celebration.
JavaScript’s original goal was to improve the user experience of web pages. Instead of
going back to the server for simple tasks such as form validation, JavaScript allowed
embedding of this functionality directly in the page. Doing so saved a rather long trip
back to the server. Imagine the frustration of filling out a long form, submitting it, and
then waiting 30–60 seconds just to get a message back indicating that you had filled in
a single field incorrectly. JavaScript can rightfully be credited with saving early Internet
users a lot of time.
The Internet Evolves
Over the decade that followed, computers and the Internet continued to evolve. To
start, both got much faster. The rapid speed-up of microprocessors, the availability of
cheap memory, and the appearance of fiber optic connections pushed the Internet into
a new age. With high-speed connections more available than ever, web pages started
becoming heavier, embedding more information and multimedia. The Web had
changed from a fairly bland landscape of interlinked documents into one filled with
different designs and interfaces. Everything changed, that is, except JavaScript.
What previously was used to save server roundtrips started to become more ubiquitous.
Where there were once dozens of lines of JavaScript code were now hundreds, and
eventually thousands. The introduction of Internet Explorer 4 and dynamic HTML
(the ability to change aspects of the page without a reload) ensured that the amount of
JavaScript on pages would only increase over time.
The last major step in the evolution of browsers was the introduction of the Document
Object Model (DOM), a unified approach to dynamic HTML that was adopted by
Internet Explorer 5, Netscape 6, and Opera. This was closely followed by the
xi
standardization of JavaScript into ECMA-262, third edition. With all browsers sup-
porting the DOM and (more or less) the same version of JavaScript, a web application
platform was born. Despite this huge leap forward, with a common API against which
to write JavaScript, the JavaScript engines in charge of executing that code remained
mostly unchanged.
Why Optimization Is Necessary
The JavaScript engines that supported web pages with a few dozen lines of JavaScript
in 1996 are the same ones running web applications with thousands of lines of Java-
Script today. In many ways, the browsers fell behind in their management of the lan-
guage and in doing the groundwork so that JavaScript could succeed at a large scale.
This became evident with Internet Explorer 6, which was heralded for its stability and
speed when it was first released but later reviled as a horrible web application platform
because of its bugs and slowness.
In reality, IE 6 hadn’t gotten any slower; it was just being asked to do more than it had
previously. The types of early web applications being created when IE 6 was introduced
in 2001 were much lighter and used much less JavaScript than those created in 2005.
The difference in the amount of JavaScript code became clear as the IE 6 JavaScript
engine struggled to keep up due to its static garbage-collection routine. The engine
looked for a fixed number of objects in memory to determine when to collect garbage.
Earlier web application developers had run into this threshold infrequently, but with
more JavaScript code comes more objects, and complex web applications began to hit
this threshold quite often. The problem became clear: JavaScript developers and web
applications had evolved while the JavaScript engines had not.
Although other browsers had more logical garbage collection routines, and somewhat
better runtime performance, most still used a JavaScript interpreter to execute code.
Code interpretation is inherently slower than compilation since there’s a translation
process between the code and the computer instructions that must be run. No matter
how smart and optimized interpreters get, they always incur a performance penalty.
Compilers are filled with all kinds of optimizations that allow developers to write code
in whatever way they want without worrying whether it’s optimal. The compiler can
determine, based on lexical analysis, what the code is attempting to do and then opti-
mize it by producing the fastest-running machine code to complete the task. Interpret-
ers have few such optimizations, which frequently means that code is executed exactly
as it is written.
In effect, JavaScript forces the developer to perform the optimizations that a compiler
would normally handle in other languages.
xii | Preface
Next-Generation JavaScript Engines
In 2008, JavaScript engines got their first big performance boost. Google introduced
their brand-new browser called Chrome. Chrome was the first browser released with
an optimizing JavaScript engine, codenamed V8. The V8 JavaScript engine is a just-in-
time (JIT) compilation engine for JavaScript, which produces machine code from Java-
Script code and then executes it. The resulting experience is blazingly fast JavaScript
execution.
Other browsers soon followed suit with their own optimizing JavaScript engines. Safari
4 features the Squirrel Fish Extreme (also called Nitro) JIT JavaScript engine, and Fire-
fox 3.5 includes the TraceMonkey engine, which optimizes frequently executed code
paths.
With these newer JavaScript engines, optimizations are being done at the compiler-
level, where they should be done. Someday, developers may be completely free of worry
about performance optimizations in their code. That day, however, is still not here.
Performance Is Still a Concern
Despite advancements in core JavaScript execution time, there are still aspects of Java-
Script that these new engines don’t handle. Delays caused by network latency and
operations affecting the appearance of the page are areas that have yet to be adequately
optimized by browsers. While simple optimizations such as function inlining, code
folding, and string concatenation algorithms are easily optimized in compilers, the dy-
namic and multifaceted structure of web applications means that these optimizations
solve only part of the performance problem.
Though newer JavaScript engines have given us a glimpse into the future of a much
faster Internet, the performance lessons of today will continue to be relevant and im-
portant for the foreseeable future.
The techniques and approaches taught in this book address many different aspects of
JavaScript, covering execution time, downloading, interaction with the DOM, page life
cycle, and more. Of these topics only a small subset, those related to core (ECMAScript)
performance, could be rendered irrelevant by advances in JavaScript engines, but that
has yet to happen.
The other topics cover ground where faster JavaScript engines won’t help: DOM in-
teraction, network latency, blocking and concurrent downloading of JavaScript, and
more. These topics will not only continue to be relevant, but will become areas of
further focus and research as low-level JavaScript execution time continues to improve.
Preface | xiii
How This Book Is Organized
The chapters in this book are organized based on a normal JavaScript development life
cycle. This begins, in Chapter 1, with the most optimal ways to load JavaScript onto
the page. Chapter 2 through Chapter 8 focus on specific programming techniques to
help your JavaScript code run as quickly as possible. Chapter 9 discusses the best ways
to build and deploy your JavaScript files to a production environment, and Chap-
ter 10 covers performance tools that can help you identify further issues once the code
is deployed. Five of the chapters were written by contributing authors:
• Chapter 3, DOM Scripting, by Stoyan Stefanov
• Chapter 5, Strings and Regular Expressions, by Steven Levithan
• Chapter 7, Ajax, by Ross Harmes
• Chapter 9, Building and Deploying High-Performance JavaScript Applications, by
Julien Lecomte
• Chapter 10, Tools, by Matt Sweeney
Each of these authors is an accomplished web developer who has made important
contributions to the web development community as a whole. Their names appear on
the opening page of their respective chapters to more easily identify their work.
JavaScript Loading
Chapter 1, Loading and Execution, starts with the basics of JavaScript: getting code
onto the page. JavaScript performance really begins with getting the code onto a page
in the most efficient way possible. This chapter focuses on the performance problems
associated with loading JavaScript code and presents several ways to mitigate the
effects.
Coding Technique
A large source of performance problems in JavaScript is poorly written code that uses
inefficient algorithms or utilities. The following seven chapters focus on identifying
problem code and presenting faster alternatives that accomplish the same task.
Chapter 2, Data Access, focuses on how JavaScript stores and accesses data within a
script. Where you store data is just as important as what you store, and this chapter
explains how concepts such as the scope chain and prototype chain can affect your
overall script performance.
Stoyan Stefanov, who is well versed in the internal workings of a web browser, wrote
Chapter 3, DOM Scripting. Stoyan explains that DOM interaction is slower than other
parts of JavaScript because of the way it is implemented. He covers all aspects of the
DOM, including a description of how repaint and reflow can slow down your code.
xiv | Preface
Chapter 4, Algorithms and Flow Control, explains how common programming para-
digms such as loops and recursion can work against you when it comes to runtime
performance. Optimization techniques such as memoization are discussed, as are
browser JavaScript runtime limitations.
Many web applications perform complex string operations in JavaScript, which is why
string expert Steven Levithan covers the topic in Chapter 5, Strings and Regular Ex-
pressions. Web developers have been fighting poor string-handling performance in
browsers for years, and Steven explains why some operations are slow and how to work
around them.
Chapter 6, Responsive Interfaces, puts the spotlight firmly on the user experience. Java-
Script can cause the browser to freeze as it executes, leaving users extremely frustrated.
This chapter discusses several techniques to ensure that the user interface remains re-
sponsive at all times.
In Chapter 7, Ajax, Ross Harmes discusses the best ways to achieve fast client-server
communication in JavaScript. Ross covers how different data formats can affect Ajax
performance and why XMLHttpRequest isn’t always the best choice.
Chapter 8, Programming Practices, is a collection of best practices that are unique to
JavaScript programming.
Deployment
Once JavaScript code is written and tested, it’s time to make the changes available to
everyone. However, you shouldn’t just push out your raw source files for use in pro-
duction. Julien Lecomte shows how to improve the performance of your JavaScript
during deployment in Chapter 9, Building and Deploying High-Performance JavaScript
Applications. Julien discusses using a build system to automatically minify files and
using HTTP compression to deliver them to the browser.
Testing
When all of your JavaScript code is deployed, the next step is to begin performance
testing. Matt Sweeney covers testing methodology and tools in Chapter 10, Tools. He
discusses how to use JavaScript to measure performance and also describes common
tools both for evaluating JavaScript runtime performance and for uncovering perform-
ance problems through HTTP sniffing.
Who This Book Is For
This book is aimed at web developers with an intermediate-to-advanced understanding
ofJavaScriptwhoarelookingtoimprovetheperformanceofwebapplicationinterfaces.
Preface | xv
Conventions Used in This Book
The following typographical conventions are used in this book:
Italic
Indicates new terms, URLs, email addresses, filenames, and file extensions.
Constant width
Used for program listings, as well as within paragraphs to refer to program elements
such as variable or function names, databases, data types, environment variables,
statements, and keywords.
Constant width bold
Shows commands or other text that should be typed literally by the user.
Constant width italic
Shows text that should be replaced with user-supplied values or by values deter-
mined by context.
This icon signifies a tip, suggestion, or general note.
This icon indicates a warning or caution.
Using Code Examples
This book is here to help you get your job done. In general, you may use the code in
this book in your programs and documentation. You do not need to contact us for
permission unless you’re reproducing a significant portion of the code. For example,
writing a program that uses several chunks of code from this book does not require
permission. Selling or distributing a CD-ROM of examples from O’Reilly books does
require permission. Answering a question by citing this book and quoting example
code does not require permission. Incorporating a significant amount of example code
from this book into your product’s documentation does require permission.
We appreciate, but do not require, attribution. An attribution usually includes the title,
author, publisher, and ISBN. For example: “High Performance JavaScript, by Nicholas
C. Zakas. Copyright 2010 Yahoo!, Inc., 978-0-596-80279-0.”
If you feel your use of code examples falls outside fair use or the permission given here,
feel free to contact us at permissions@oreilly.com.
xvi | Preface
Safari® Books Online
Safari Books Online is an on-demand digital library that lets you easily
search over 7,500 technology and creative reference books and videos to
find the answers you need quickly.
Withasubscription,youcanreadanypageandwatchanyvideofromourlibraryonline.
Read books on your cell phone and mobile devices. Access new titles before they are
available for print, and get exclusive access to manuscripts in development and post
feedback for the authors. Copy and paste code samples, organize your favorites, down-
load chapters, bookmark key sections, create notes, print out pages, and benefit from
tons of other time-saving features.
O’Reilly Media has uploaded this book to the Safari Books Online service. To have full
digital access to this book and others on similar topics from O’Reilly and other pub-
lishers, sign up for free at http://my.safaribooksonline.com.
How to Contact Us
Please address comments and questions concerning this book to the publisher:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
800-998-9938 (in the United States or Canada)
707-829-0515 (international or local)
707-829-0104 (fax)
We have a web page for this book, where we list errata, examples, and any additional
information. You can access this page at:
http://www.oreilly.com/catalog/9780596802790
To comment or ask technical questions about this book, send email to:
bookquestions@oreilly.com
For more information about our books, conferences, Resource Centers, and the
O’Reilly Network, see our website at:
http://www.oreilly.com
Preface | xvii
Acknowledgments
First and foremost, I’d like to thank all of the contributing authors: Matt Sweeney,
Stoyan Stefanov, Stephen Levithan, Ross Harmes, and Julien Lecomte. Having their
combined expertise and knowledge as part of this book made the process more exciting
and the end result more compelling.
Thanks to all of the performance gurus of the world that I’ve had the opportunity to
meet and interact with, especially Steve Souders, Tenni Theurer, and Nicole Sullivan.
You three helped expand my horizons when it comes to web performance, and I’m
incredibly grateful for that.
A big thanks to everyone who reviewed the book prior to publication, including Ryan
Grove, Oliver Hunt, Matthew Russell, Ted Roden, Remy Sharp, and Venkateswaran
Udayasankar. Their early feedback was invaluable in preparing the book for
production.
And a huge thanks to everyone at O’Reilly and Yahoo! that made this book possible.
I’ve wanted to write a book for Yahoo! ever since I joined the company in 2006, and
Yahoo! Press was a great way to make this happen.
xviii | Preface
CHAPTER 1
Loading and Execution
JavaScript performance in the browser is arguably the most important usability issue
facingdevelopers.TheproblemiscomplexbecauseoftheblockingnatureofJavaScript,
which is to say that nothing else can happen while JavaScript code is being executed.
In fact, most browsers use a single process for both user interface (UI) updates and
JavaScript execution, so only one can happen at any given moment in time. The longer
JavaScript takes to execute, the longer it takes before the browser is free to respond to
user input.
On a basic level, this means that the very presence of a <script> tag is enough to make
the page wait for the script to be parsed and executed. Whether the actual JavaScript
code is inline with the tag or included in an external file is irrelevant; the page download
and rendering must stop and wait for the script to complete before proceeding. This is
a necessary part of the page’s life cycle because the script may cause changes to the page
while executing. The typical example is using document.write() in the middle of a page
(as often used by advertisements). For example:
<html>
<head>
<title>Script Example</title>
</head>
<body>
<p>
<script type="text/javascript">
document.write("The date is " + (new Date()).toDateString());
</script>
</p>
</body>
</html>
When the browser encounters a <script> tag, as in this HTML page, there is no way
of knowing whether the JavaScript will insert content into the <p>, introduce additional
elements, or perhaps even close the tag. Therefore, the browser stops processing the
page as it comes in, executes the JavaScript code, then continues parsing and rendering
the page. The same takes place for JavaScript loaded using thesrc attribute; the browser
must first download the code from the external file, which takes time, and then parse
1
and execute the code. Page rendering and user interaction are completely blocked dur-
ing this time.
The two leading sources of information on JavaScript affecting page
download performance are the Yahoo! Exceptional Performance team
(http://developer.yahoo.com/performance/) and Steve Souders, author of
High Performance Web Sites (O’Reilly) and Even Faster Web Sites (O’Re-
illy). This chapter is heavily influenced by their combined research.
Script Positioning
The HTML 4 specification indicates that a <script> tag may be placed inside of a
<head> or <body> tag in an HTML document and may appear any number of times
within each. Traditionally, <script> tags that are used to load external JavaScript files
have appeared in the <head>, along with <link> tags to load external CSS files and other
metainformation about the page. The theory was that it’s best to keep as many style
and behavior dependencies together, loading them first so that the page will come in
looking and behaving correctly. For example:
<html>
<head>
<title>Script Example</title>
<-- Example of inefficient script positioning -->
<script type="text/javascript" src="file1.js"></script>
<script type="text/javascript" src="file2.js"></script>
<script type="text/javascript" src="file3.js"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<p>Hello world!</p>
</body>
</html>
Though this code seems innocuous, it actually has a severe performance issue: there
are three JavaScript files being loaded in the <head>. Since each <script> tag blocks the
page from continuing to render until it has fully downloaded and executed the Java-
Script code, the perceived performance of this page will suffer. Keep in mind that
browsers don’t start rendering anything on the page until the opening <body> tag is
encountered. Putting scripts at the top of the page in this way typically leads to a no-
ticeable delay, often in the form of a blank white page, before the user can even begin
reading or otherwise interacting with the page. To get a good understanding of how
this occurs, it’s useful to look at a waterfall diagram showing when each resource is
downloaded. Figure 1-1 shows when each script and the stylesheet file get downloaded
as the page is loading.
Figure 1-1 shows an interesting pattern. The first JavaScript file begins to download
and blocks any of the other files from downloading in the meantime. Further, there is
2 | Chapter 1: Loading and Execution
a delay between the time at which file1.js is completely downloaded and the time at
which file2.js begins to download. That space is the time it takes for the code contained
in file1.js to fully execute. Each file must wait until the previous one has been down-
loaded and executed before the next download can begin. In the meantime, the user is
met with a blank screen as the files are being downloaded one at a time. This is the
behavior of most major browsers today.
Internet Explorer 8, Firefox 3.5, Safari 4, and Chrome 2 all allow parallel downloads
of JavaScript files. This is good news because the <script> tags don’t necessarily block
other <script> tags from downloading external resources. Unfortunately, JavaScript
downloadsstillblockdownloadingofotherresources,suchasimages.Andeventhough
downloading a script doesn’t block other scripts from downloading, the page must still
wait for the JavaScript code to be downloaded and executed before continuing. So while
the latest browsers have improved performance by allowing parallel downloads, the
problem hasn’t been completely solved. Script blocking still remains a problem.
Because scripts block downloading of all resource types on the page, it’s recommended
to place all <script> tags as close to the bottom of the <body> tag as possible so as not
to affect the download of the entire page. For example:
<html>
<head>
<title>Script Example</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<p>Hello world!</p>
<-- Example of recommended script positioning -->
<script type="text/javascript" src="file1.js"></script>
<script type="text/javascript" src="file2.js"></script>
<script type="text/javascript" src="file3.js"></script>
</body>
</html>
This code represents the recommended position for <script> tags in an HTML file.
Even though the script downloads will block one another, the rest of the page has
Figure 1-1. JavaScript code execution blocks other file downloads
Script Positioning | 3
already been downloaded and displayed to the user so that the entire page isn’t per-
ceived as slow. This is the Yahoo! Exceptional Performance team’s first rule about
JavaScript: put scripts at the bottom.
Grouping Scripts
Since each <script> tag blocks the page from rendering during initial download, it’s
helpful to limit the total number of <script> tags contained in the page. This applies
to both inline scripts as well as those in external files. Every time a <script> tag is
encountered during the parsing of an HTML page, there is going to be a delay while
the code is executed; minimizing these delays improves the overall performance of the
page.
Steve Souders has also found that an inline script placed after a <link>
tag referencing an external stylesheet caused the browser to block while
waiting for the stylesheet to download. This is done to ensure that the
inline script will have the most correct style information with which to
work. Souders recommends never putting an inline script after a
<link> tag for this reason.
The problem is slightly different when dealing with external JavaScript files. Each
HTTP request brings with it additional performance overhead, so downloading one
single 100 KB file will be faster than downloading four 25 KB files. To that end, it’s
helpful to limit the number of external script files that your page references.
Typically, a large website or web application will have several required JavaScript files.
You can minimize the performance impact by concatenating these files together into a
single file and then calling that single file with a single <script> tag. The concatenation
can happen offline using a build tool (discussed in Chapter 9) or in real-time using a
tool such as the Yahoo! combo handler.
Yahoo! created the combo handler for use in distributing the Yahoo! User Interface
(YUI) library files through their Content Delivery Network (CDN). Any website can
pull in any number of YUI files by using a combo-handled URL and specifying the files
to include. For example, this URL includes two files: http://yui.yahooapis.com/combo
?2.7.0/build/yahoo/yahoo-min.js&2.7.0/build/event/event-min.js.
This URL loads the 2.7.0 versions of the yahoo-min.js and event-min.js files. These files
exist separately on the server but are combined when this URL is requested. Instead of
using two <script> tags (one to load each file), a single <script> tag can be used to load
both:
4 | Chapter 1: Loading and Execution
<html>
<head>
<title>Script Example</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<p>Hello world!</p>
<-- Example of recommended script positioning -->
<script type="text/javascript" src="
http://yui.yahooapis.com/combo?2.7.0/build/yahoo/yahoo-min.js&
2.7.0/build/event/event-min.js "></script>
</body>
</html>
This code has a single <script> tag at the bottom of the page that loads multiple Java-
Script files, showing the best practice for including external JavaScript on an HTML
page.
Nonblocking Scripts
JavaScript’s tendency to block browser processes, both HTTP requests and UI updates,
is the most notable performance issue facing developers. Keeping JavaScript files small
and limiting the number of HTTP requests are only the first steps in creating a respon-
sive web application. The richer the functionality an application requires, the more
JavaScript code is required, and so keeping source code small isn’t always an option.
Limiting yourself to downloading a single large JavaScript file will only result in locking
the browser out for a long period of time, despite it being just one HTTP request. To
get around this situation, you need to incrementally add more JavaScript to the page
in a way that doesn’t block the browser.
The secret to nonblocking scripts is to load the JavaScript source code after the page
has finished loading. In technical terms, this means downloading the code after the
window’s load event has been fired. There are a few techniques for achieving this result.
Deferred Scripts
HTML 4 defines an additional attribute for the <script> tag called defer. The defer
attribute indicates that the script contained within the element is not going to modify
the DOM and therefore execution can be safely deferred until a later point in time. The
defer attribute is supported only in Internet Explorer 4+ and Firefox 3.5+, making it
less than ideal for a generic cross-browser solution. In other browsers, the defer at-
tribute is simply ignored and so the <script> tag is treated in the default (blocking)
manner. Still, this solution is useful if your target browsers support it. The following is
an example usage:
<script type="text/javascript" src="file1.js" defer></script>
Nonblocking Scripts | 5
A <script> tag with defer may be placed anywhere in the document. The JavaScript
file will begin downloading at the point that the <script> tag is parsed, but the code
will not be executed until the DOM has been completely loaded (before the onload
event handler is called). When a deferred JavaScript file is downloaded, it doesn’t block
the browser’s other processes, and so these files can be downloaded in parallel with
others on the page.
Any <script> element marked with defer will not execute until after the DOM has been
completely loaded; this holds true for inline scripts as well as for external script files.
The following simple page demonstrates how the defer attribute alters the behavior of
scripts:
<html>
<head>
<title>Script Defer Example</title>
</head>
<body>
<script defer>
alert("defer");
</script>
<script>
alert("script");
</script>
<script>
window.onload = function(){
alert("load");
};
</script>
</body>
</html>
This code displays three alerts as the page is being processed. In browsers that don’t
support defer, the order of the alerts is “defer”, “script”, and “load”. In browsers that
support defer, the order of the alerts is “script”, “defer”, and “load”. Note that the
deferred <script> element isn’t executed until after the second but is executed before
the onload event handler is called.
If your target browsers include only Internet Explorer and Firefox 3.5, then deferring
scripts in this manner can be helpful. If you have a larger cross-section of browsers to
support, there are other solutions that work in a more consistent manner.
Dynamic Script Elements
The Document Object Model (DOM) allows you to dynamically create almost any part
of an HTML document using JavaScript. At its root, the <script> element isn’t any
different than any other element on a page: references can be retrieved through the
DOM, and they can be moved, removed from the document, and even created. A new
<script> element can be created very easily using standard DOM methods:
6 | Chapter 1: Loading and Execution
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "file1.js";
document.getElementsByTagName("head")[0].appendChild(script);
This new <script> element loads the source file file1.js. The file begins downloading
as soon as the element is added to the page. The important thing about this technique
is that the file is downloaded and executed without blocking other page processes,
regardless of where the download is initiated. You can even place this code in the
<head> of a document without affecting the rest of the page (aside from the one HTTP
connection that is used to download the file).
It’s generally safer to add new <script> nodes to the <head> element
instead of the <body>, especially if this code is executing during page
load. Internet Explorer may experience an “operation aborted” error if
all of the <body> contents have not yet been loaded.*
When a file is downloaded using a dynamic script node, the retrieved code is typically
executed immediately (except in Firefox and Opera, which will wait until any previous
dynamic script nodes have executed). This works well when the script is self-executing
but can be problematic if the code contains only interfaces to be used by other scripts
on the page. In that case, you need to track when the code has been fully downloaded
and is ready for use. This is accomplished using events that are fired by the dynamic
<script> node.
Firefox, Opera, Chrome, and Safari 3+ all fire a load event when the src of a
<script> element has been retrieved. You can therefore be notified when the script is
ready by listening for this event:
var script = document.createElement("script")
script.type = "text/javascript";
//Firefox, Opera, Chrome, Safari 3+
script.onload = function(){
alert("Script loaded!");
};
script.src = "file1.js";
document.getElementsByTagName("head")[0].appendChild(script);
Internet Explorer supports an alternate implementation that fires a readystatechange
event. There is a readyState property on the <script> element that is changed at various
times during the download of an external file. There are five possible values for ready
State:
* See “The dreaded operation aborted error” at http://www.nczonline.net/blog/2008/03/17/the
-dreaded-operation-aborted-error/ for a more in-depth discussion of this issue.
Nonblocking Scripts | 7
"uninitialized"
The default state
"loading"
Download has begun
"loaded"
Download has completed
"interactive"
Data is completely downloaded but isn’t fully available
"complete"
All data is ready to be used
Microsoft’s documentation for readyState and each of the possible values seems to
indicate that not all states will be used during the lifetime of the <script> element, but
there is no indication as to which will always be used. In practice, the two states of most
interest are "loaded" and "complete". Internet Explorer is inconsistent with which of
these two readyState values indicates the final state, as sometimes the <script> element
will reach the "loaded" state but never reach "complete" whereas other times "com
plete" will be reached without "loaded" ever having been used. The safest way to use
the readystatechange event is to check for both of these states and remove the event
handler when either one occurs (to ensure the event isn’t handled twice):
var script = document.createElement("script")
script.type = "text/javascript";
//Internet Explorer
script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
alert("Script loaded.");
}
};
script.src = "file1.js";
document.getElementsByTagName("head")[0].appendChild(script);
In most cases, you’ll want to use a single approach to dynamically load JavaScript files.
The following function encapsulates both the standard and IE-specific functionality:
function loadScript(url, callback){
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
8 | Chapter 1: Loading and Execution
} else { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
This function accepts two arguments: the URL of the JavaScript file to retrieve and a
callback function to execute when the JavaScript has been fully loaded. Feature detec-
tion is used to determine which event handler should monitor the script’s progress.
The last step is to assign the src property and add the <script> element to the page.
The loadScript() function is used as follows:
loadScript("file1.js", function(){
alert("File is loaded!");
});
You can dynamically load as many JavaScript files as necessary on a page, but make
sure you consider the order in which files must be loaded. Of all the major browsers,
only Firefox and Opera guarantee that the order of script execution will remain the
same as you specify. Other browsers will download and execute the various code files
in the order in which they are returned from the server. You can guarantee the order
by chaining the downloads together, such as:
loadScript("file1.js", function(){
loadScript("file2.js", function(){
loadScript("file3.js", function(){
alert("All files are loaded!");
});
});
});
This code waits to begin loading file2.js until file1.js is available and also waits to
download file3.js until file2.js is available. Though possible, this approach can get a
little bit difficult to manage if there are multiple files to download and execute.
If the order of multiple files is important, the preferred approach is to concatenate the
files into a single file where each part is in the correct order. That single file can then
be downloaded to retrieve all of the code at once (since this is happening asynchro-
nously, there’s no penalty for having a larger file).
Dynamic script loading is the most frequently used pattern for nonblocking JavaScript
downloads due to its cross-browser compatibility and ease of use.
XMLHttpRequest Script Injection
Another approach to nonblocking scripts is to retrieve the JavaScript code using an
XMLHttpRequest (XHR) object and then inject the script into the page. This technique
Nonblocking Scripts | 9
involves creating an XHR object, downloading the JavaScript file, then injecting the
JavaScript code into the page using a dynamic <script> element. Here’s a simple
example:
var xhr = new XMLHttpRequest();
xhr.open("get", "file1.js", true);
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
var script = document.createElement("script");
script.type = "text/javascript";
script.text = xhr.responseText;
document.body.appendChild(script);
}
}
};
xhr.send(null);
This code sends a GET request for the file file1.js. The onreadystatechange event handler
checks for a readyState of 4 and then verifies that the HTTP status code is valid (any-
thing in the 200 range means a valid response, and 304 means a cached response). If a
valid response has been received, then a new <script> element is created and its text
property is assigned to the responseText received from the server. Doing so essentially
creates a <script> element with inline code. Once the new <script> element is added
to the document, the code is executed and is ready to use.
The primary advantage of this approach is that you can download the JavaScript code
without executing it immediately. Since the code is being returned outside of a
<script> tag, it won’t automatically be executed upon download, allowing you to defer
its execution until you’re ready. Another advantage is that the same code works in all
modern browsers without exception cases.
The primary limitation of this approach is that the JavaScript file must be located on
the same domain as the page requesting it, which makes downloading from CDNs
impossible. For this reason, XHR script injection typically isn’t used on large-scale web
applications.
Recommended Nonblocking Pattern
The recommend approach to loading a significant amount of JavaScript onto a page is
a two-step process: first, include the code necessary to dynamically load JavaScript,
and then load the rest of the JavaScript code needed for page initialization. Since the
first part of the code is as small as possible, potentially containing just the load
Script() function, it downloads and executes quickly, and so shouldn’t cause much
interference with the page. Once the initial code is in place, use it to load the remaining
JavaScript. For example:
10 | Chapter 1: Loading and Execution
<script type="text/javascript" src="loader.js"></script>
<script type="text/javascript">
loadScript("the-rest.js", function(){
Application.init();
});
</script>
Place this loading code just before the closing </body> tag. Doing so has several benefits.
First, as discussed earlier, this ensures that JavaScript execution won’t prevent the rest
of the page from being displayed. Second, when the second JavaScript file has finished
downloading, all of the DOM necessary for the application has been created and is
ready to be interacted with, avoiding the need to check for another event (such as
window.onload) to know when the page is ready for initialization.
Another option is to embed the loadScript() function directly into the page, thus
avoiding another HTTP request. For example:
<script type="text/javascript">
function loadScript(url, callback){
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" ||
script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
loadScript("the-rest.js", function(){
Application.init();
});
</script>
If you decide to take the latter approach, it’s recommended to minify the initial script
using a tool such as YUI Compressor (see Chapter 9) for the smallest byte-size impact
on your page.
Once the code for page initialization has been completely downloaded, you are free to
continue using loadScript() to load additional functionality onto the page as needed.
Nonblocking Scripts | 11
The YUI 3 approach
The concept of a small initial amount of code on the page followed by downloading
additional functionality is at the core of the YUI 3 design. To use YUI 3 on your page,
begin by including the YUI seed file:
<script type="text/javascript"
src="http://yui.yahooapis.com/combo?3.0.0/build/yui/yui-min.js"></script>
The seed file is around 10 KB (6 KB gzipped) and includes enough functionality to
download any other YUI components from the Yahoo! CDN. For example, if you’d
like to use the DOM utility, you specify its name ("dom") with the YUI use() method
and then provide a callback that will be executed when the code is ready:
YUI().use("dom", function(Y){
Y.DOM.addClass(docment.body, "loaded");
});
This example creates a new instance of the YUI object and then calls the use() method.
The seed file has all of the information about filenames and dependencies, so specifying
"dom" actually builds up a combo-handler URL with all of the correct dependency files
and creates a dynamic script element to download and execute those files. When all of
the code is available, the callback method is called and the YUI instance is passed in as
the argument, allowing you to immediately start using the newly downloaded
functionality.
The LazyLoad library
For a more general-purpose tool, Ryan Grove of Yahoo! Search created the LazyLoad
library (available at http://github.com/rgrove/lazyload/). LazyLoad is a more powerful
version of the loadScript() function. When minified, the LazyLoad file is around 1.5
KB (minified, not gzipped). Example usage:
<script type="text/javascript" src="lazyload-min.js"></script>
<script type="text/javascript">
LazyLoad.js("the-rest.js", function(){
Application.init();
});
</script>
LazyLoad is also capable of downloading multiple JavaScript files and ensuring that
they are executed in the correct order in all browsers. To load multiple JavaScript files,
just pass an array of URLs to the LazyLoad.js() method:
<script type="text/javascript" src="lazyload-min.js"></script>
<script type="text/javascript">
LazyLoad.js(["first-file.js", "the-rest.js"], function(){
Application.init();
});
</script>
12 | Chapter 1: Loading and Execution
Even though the files are downloaded in a nonblocking fashion using dynamic script
loading, it’s recommended to have as few files as possible. Each download is still a
separate HTTP request, and the callback function won’t execute until all of the files
have been downloaded and executed.
LazyLoad is also capable of loading CSS files dynamically. This is typi-
cally less of an issue because CSS file downloads are always done in
parallel and don’t block other page activities.
The LABjs library
Another take on nonblocking JavaScript loading is LABjs (http://labjs.com/), an open
source library written by Kyle Simpson with input from Steve Souders. This library
provides more fine-grained control over the loading process and tries to download as
much code in parallel as possible. LABjs is also quite small, 4.5 KB (minified, not
gzipped), and so has a minimal page footprint. Example usage:
<script type="text/javascript" src="lab.js"></script>
<script type="text/javascript">
$LAB.script("the-rest.js")
.wait(function(){
Application.init();
});
</script>
The $LAB.script() method is used to define a JavaScript file to download, whereas
$LAB.wait() is used to indicate that execution should wait until the file is downloaded
and executed before running the given function. LABjs encourages chaining, so every
method returns a reference to the $LAB object. To download multiple JavaScript files,
just chain another $LAB.script() call:
<script type="text/javascript" src="lab.js"></script>
<script type="text/javascript">
$LAB.script("first-file.js")
.script("the-rest.js")
.wait(function(){
Application.init();
});
</script>
What sets LABjs apart is its ability to manage dependencies. Normal inclusion with
<script> tags means that each file is downloaded (either sequentially or in parallel, as
mentioned previously) and then executed sequentially. In some cases this is truly nec-
essary, but in others it is not.
LABjs allows you to specify which files should wait for others by using wait(). In the
previous example, the code in first-file.js is not guaranteed to execute before the code
in the-rest.js. To guarantee this, you must add a wait() call after the first script():
Nonblocking Scripts | 13
<script type="text/javascript" src="lab.js"></script>
<script type="text/javascript">
$LAB.script("first-file.js").wait()
.script("the-rest.js")
.wait(function(){
Application.init();
});
</script>
Now the code in first-file.js is guaranteed to execute before the code in the-rest.js, al-
though the contents of the files are downloaded in parallel.
Summary
Managing JavaScript in the browser is tricky because code execution blocks other
browser processes such as UI painting. Every time a <script> tag is encountered, the
page must stop and wait for the code to download (if external) and execute before
continuing to process the rest of the page. There are, however, several ways to minimize
the performance impact of JavaScript:
• Put all <script> tags at the bottom of the page, just inside of the closing </body>
tag. This ensures that the page can be almost completely rendered before script
execution begins.
• Group scripts together. The fewer <script> tags on the page, the faster the page
can be loaded and become interactive. This holds true both for <script> tags load-
ing external JavaScript files and those with inline code.
• There are several ways to download JavaScript in a nonblocking fashion:
—Use the defer attribute of the <script> tag (Internet Explorer and Firefox 3.5+
only)
—Dynamically create <script> elements to download and execute the code
—Download the JavaScript code using an XHR object, and then inject the code
into the page
By using these strategies, you can greatly improve the perceived performance of a web
application that requires a large amount of JavaScript code.
14 | Chapter 1: Loading and Execution
CHAPTER 2
Data Access
One of the classic computer science problems is determining where data should be
stored for optimal reading and writing. Where data is stored is related to how quickly
it can be retrieved during code execution. This problem in JavaScript is somewhat
simplified because of the small number of options for data storage. Similar to other
languages, though, where data is stored can greatly affect how quickly it can be accessed
later. There are four basic places from which data can be accessed in JavaScript:
Literal values
Any value that represents just itself and isn’t stored in a particular location. Java-
Script can represent strings, numbers, Booleans, objects, arrays, functions, regular
expressions, and the special values null and undefined as literals.
Variables
Any developer-defined location for storing data created by using the var keyword.
Array items
A numerically indexed location within a JavaScript Array object.
Object members
A string-indexed location within a JavaScript object.
Each of these data storage locations has a particular cost associated with reading and
writing operations involving the data. In most cases, the performance difference be-
tween accessing information from a literal value versus a local variable is trivial. Ac-
cessing information from array items and object members is more expensive, though
exactly which is more expensive depends heavily on the browser. Figure 2-1 shows the
relative speed of accessing 200,000 values from each of these four locations in various
browsers.
Older browsers using more traditional JavaScript engines, such as Firefox 3, Internet
Explorer, and Safari 3.2, show a much larger amount of time taken to access values
versus browsers that use optimizing JavaScript engines. The general trends, however,
remain the same across all browsers: literal value and local variable access tend to be
faster than array item and object member access. The one exception, Firefox 3,
15
optimized array item access to be much faster. Even so, the general advice is to use
literal values and local variables whenever possible and limit use of array items and
object members where speed of execution is a concern. To that end, there are several
patterns to look for, avoid, and optimize in your code.
Managing Scope
The concept of scope is key to understanding JavaScript not just from a performance
perspective, but also from a functional perspective. Scope has many effects in Java-
Script, from determining what variables a function can access to assigning the value of
this. There are also performance considerations when dealing with JavaScript scopes,
but to understand how speed relates to scope, it’s necessary to understand exactly how
scope works.
Scope Chains and Identifier Resolution
Every function in JavaScript is represented as an object—more specifically, as an in-
stance of Function. Function objects have properties just like any other object, and these
includeboththepropertiesthatyoucanaccessprogrammaticallyandaseriesofinternal
properties that are used by the JavaScript engine but are not accessible through code.
One of these properties is [[Scope]], as defined by ECMA-262, Third Edition.
Figure 2-1. Time per 200,000 reads from various data locations
16 | Chapter 2: Data Access
The internal [[Scope]] property contains a collection of objects representing the scope
in which the function was created. This collection is called the function’s scope chain
and it determines the data that a function can access. Each object in the function’s
scope chain is called a variable object, and each of these contains entries for variables
in the form of key-value pairs. When a function is created, its scope chain is populated
with objects representing the data that is accessible in the scope in which the function
was created. For example, consider the following global function:
function add(num1, num2){
var sum = num1 + num2;
return sum;
}
When the add() function is created, its scope chain is populated with a single variable
object: the global object representing all of the variables that are globally defined. This
global object contains entries for window, navigator, and document, to name a few.
Figure 2-2 shows this relationship (note the global object in this figure shows only a
few of the global variables as an example; there are many others).
Figure 2-2. Scope chain for the add() function
The add function’s scope chain is later used when the function is executed. Suppose
that the following code is executed:
var total = add(5, 10);
Executing the add function triggers the creation of an internal object called an execution
context. An execution context defines the environment in which a function is being
executed. Each execution context is unique to one particular execution of the function,
and so multiple calls to the same function result in multiple execution contexts being
created. The execution context is destroyed once the function has been completely
executed.
Managing Scope | 17
An execution context has its own scope chain that is used for identifier resolution.
When the execution context is created, its scope chain is initialized with the objects
contained in the executing function’s [[Scope]] property. These values are copied over
into the execution context scope chain in the order in which they appear in the function.
Once this is complete, a new object called the activation object is created for the exe-
cution context. The activation object acts as the variable object for this execution and
contains entries for all local variables, named arguments, the arguments collection, and
this. This object is then pushed to the front of the scope chain. When the execution
context is destroyed, so is the activation object. Figure 2-3 shows the execution context
and its scope chain for the previous example code.
Figure 2-3. Scope chain while executing add()
Each time a variable is encountered during the function’s execution, the process of
identifier resolution takes place to determine where to retrieve or store the data. During
this process, the execution context’s scope chain is searched for an identifier with the
samename.Thesearchbeginsatthefrontofthescopechain,intheexecutionfunction’s
activation object. If found, the variable with the specified identifier is used; if not, the
search continues on to the next object in the scope chain. This process continues until
either the identifier is found or there are no more variable objects to search, in which
case the identifier is deemed to be undefined. The same approach is taken for each
identifier found during the function execution, so in the previous example, this would
happen for sum, num1, and num2. It is this search process that affects performance.
18 | Chapter 2: Data Access
Note that two variables with the same name may exist in different parts
of the scope chain. In that case, the identifier is bound to the variable
that is found first in the scope chain traversal, and the first variable is
said to shadow the second.
Identifier Resolution Performance
Identifier resolution isn’t free, as in fact no computer operation really is without some
sort of performance overhead. The deeper into the execution context’s scope chain an
identifier exists, the slower it is to access for both reads and writes. Consequently, local
variables are always the fastest to access inside of a function, whereas global variables
will generally be the slowest (optimizing JavaScript engines are capable of tuning this
in certain situations). Keep in mind that global variables always exist in the last variable
object of the execution context’s scope chain, so they are always the furthest away to
resolve. Figures 2-4 and 2-5 show the speed of identifier resolution based on their depth
in the scope chain. A depth of 1 indicates a local variable.
Figure 2-4. Identifier resolution for write operations
Managing Scope | 19
Figure 2-5. Identifier resolution for read operations
The general trend across all browsers is that the deeper into the scope chain an identifier
exists, the slower it will be read from or written to. Browsers with optimizing JavaScript
engines, such as Chrome and Safari 4, don’t have this sort of performance penalty for
accessing out-of-scope identifiers, whereas Internet Explorer, Safari 3.2, and others
show a more drastic effect. It’s worth noting that earlier browsers, such as Internet
Explorer 6 and Firefox 2, had incredibly steep slopes and would not even appear within
the bounds of this graph at the high point if their data had been included.
Given this information, it’s advisable to use local variables whenever possible to im-
prove performance in browsers without optimizing JavaScript engines. A good rule of
thumb is to always store out-of-scope values in local variables if they are used more
than once within a function. Consider the following example:
function initUI(){
var bd = document.body,
links = document.getElementsByTagName("a"),
i= 0,
len = links.length;
while(i < len){
update(links[i++]);
}
20 | Chapter 2: Data Access
document.getElementById("go-btn").onclick = function(){
start();
};
bd.className = "active";
}
This function contains three references to document, which is a global object. The search
for this variable must go all the way through the scope chain before finally being re-
solved in the global variable object. You can mitigate the performance impact of re-
peated global variable access by first storing the reference in a local variable and then
using the local variable instead of the global. For example, the previous code can be
rewritten as follows:
function initUI(){
var doc = document,
bd = doc.body,
links = doc.getElementsByTagName("a"),
i= 0,
len = links.length;
while(i < len){
update(links[i++]);
}
doc.getElementById("go-btn").onclick = function(){
start();
};
bd.className = "active";
}
The updated version of initUI() first stores a reference to document in the local doc
variable. Instead of accessing a global variables three times, that number is cut down
to one. Accessing doc instead of document is faster because it’s a local variable. Of course,
this simplistic function won’t show a huge performance improvement, because it’s not
doing that much, but imagine larger functions with dozens of global variables being
accessed repeatedly; that is where the more impressive performance improvements will
be found.
Scope Chain Augmentation
Generally speaking, an execution context’s scope chain doesn’t change. There are,
however, two statements that temporarily augment the execution context’s scope chain
while it is being executed. The first of these is with.
The with statement is used to create variables for all of an object’s properties. This
mimics other languages with similar features and is usually seen as a convenience to
avoid writing the same code repeatedly. The initUI() function can be written as the
following:
Managing Scope | 21
function initUI(){
with (document){ //avoid!
var bd = body,
links = getElementsByTagName("a"),
i= 0,
len = links.length;
while(i < len){
update(links[i++]);
}
getElementById("go-btn").onclick = function(){
start();
};
bd.className = "active";
}
}
This rewritten version of initUI() uses a with statement to avoid writing document else-
where. Though this may seem more efficient, it actually creates a performance problem.
When code execution flows into a with statement, the execution context’s scope chain
is temporarily augmented. A new variable object is created containing all of the prop-
erties of the specified object. That object is then pushed to the front of the scope chain,
meaning that all of the function’s local variables are now in the second scope chain
object and are therefore more expensive to access (see Figure 2-6).
By passing the document object into the with statement, a new variable object containing
all of the document object’s properties is pushed to the front of the scope chain. This
makes it very fast to access document properties but slower to access the local variables
such as bd. For this reason, it’s best to avoid using the with statement. As shown pre-
viously, it’s just as easy to store document in a local variable and get the performance
improvement that way.
The with statement isn’t the only part of JavaScript that artificially augments the exe-
cution context’s scope chain; the catch clause of the try-catch statement has the same
effect. When an error occurs in the try block, execution automatically flows to the
catch and the exception object is pushed into a variable object that is then placed at
the front of the scope chain. Inside of the catch block, all variables local to the function
are now in the second scope chain object. For example:
try {
methodThatMightCauseAnError();
} catch (ex){
alert(ex.message); //scope chain is augmented here
}
Note that as soon as the catch clause is finished executing, the scope chain returns to
its previous state.
22 | Chapter 2: Data Access
The try-catch statement is very useful when applied appropriately, and so it doesn’t
make sense to suggest complete avoidance. If you do plan on using a try-catch, make
sure that you understand the likelihood of error. A try-catch should never be used as
the solution to a JavaScript error. If you know an error will occur frequently, then that
indicates a problem with the code itself that should be fixed.
You can minimize the performance impact of the catch clause by executing as little
code as necessary within it. A good pattern is to have a method for handling errors that
the catch clause can delegate to, as in this example:
try {
methodThatMightCauseAnError();
} catch (ex){
handleError(ex); //delegate to handler method
}
Here a handleError() method is the only code that is executed in the catch clause. This
method is free to handle the error in an appropriate way and is passed the exception
object generated from the error. Since there is just one statement executed and no local
Figure 2-6. Augmented scope chain in a with statement
Managing Scope | 23
variables accessed, the temporary scope chain augmentation does not affect the per-
formance of the code.
Dynamic Scopes
Both the with statement and the catch clause of a try-catch statement, as well as a
function containing eval(), are all considered to be dynamic scopes. A dynamic scope
is one that exists only through execution of code and therefore cannot be determined
simply by static analysis (looking at the code structure). For example:
function execute(code) {
eval(code);
function subroutine(){
return window;
}
var w = subroutine();
//what value is w?
};
The execute() function represents a dynamic scope due to the use of eval(). The value
of w can change based on the value of code. In most cases, w will be equal to the global
window object, but consider the following:
execute("var window = {};")
In this case, eval() creates a local window variable in execute(), so w ends up equal to
the local window instead of the global. There is no way to know if this is the case until
the code is executed, which means the value of the window identifier cannot be
predetermined.
Optimizing JavaScript engines such as Safari’s Nitro try to speed up identifier resolution
by analyzing the code to determine which variables should be accessible at any given
time. These engines try to avoid the traditional scope chain lookup by indexing iden-
tifiers for faster resolution. When a dynamic scope is involved, however, this optimi-
zation is no longer valid. The engines need to switch back to a slower hash-based
approach for identifier resolution that more closely mirrors traditional scope chain
lookup.
For this reason, it’s recommended to use dynamic scopes only when absolutely
necessary.
Closures, Scope, and Memory
Closures are one of the most powerful aspects of JavaScript, allowing a function to
access data that is outside of its local scope. The use of closures has been popularized
through the writings of Douglas Crockford and is now ubiquitous in most complex
24 | Chapter 2: Data Access
web applications. There is, however, a performance impact associated with using
closures.
To understand the performance issues with closures, consider the following:
function assignEvents(){
var id = "xdi9592";
document.getElementById("save-btn").onclick = function(event){
saveDocument(id);
};
}
The assignEvents() function assigns an event handler to a single DOM element. This
event handler is a closure, as it is created when the assignEvents() is executed and can
access the id variable from the containing scope. In order for this closure to access id,
a specific scope chain must be created.
When assignEvents() is executed, an activation object is created that contains, among
other things, the id variable. This becomes the first object in the execution context’s
scope chain, with the global object coming second. When the closure is created, its
[[Scope]] property is initialized with both of these objects (see Figure 2-7).
Figure 2-7. Scope chains of the assignEvents() execution context and closure
Since the closure’s [[Scope]] property contains references to the same objects as the
execution context’s scope chain, there is a side effect. Typically, a function’s activation
object is destroyed when the execution context is destroyed. When there’s a closure
involved, though, the activation object isn’t destroyed, because a reference still exists
Managing Scope | 25
Another Random Scribd Document
with Unrelated Content
High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas
High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas
High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas
The Project Gutenberg eBook of Gunpowder
and Ammunition, Their Origin and Progress
This ebook is for the use of anyone anywhere in the United
States and most other parts of the world at no cost and with
almost no restrictions whatsoever. You may copy it, give it away
or re-use it under the terms of the Project Gutenberg License
included with this ebook or online at www.gutenberg.org. If you
are not located in the United States, you will have to check the
laws of the country where you are located before using this
eBook.
Title: Gunpowder and Ammunition, Their Origin and Progress
Author: H. W. L. Hime
Release date: March 22, 2017 [eBook #54411]
Most recently updated: October 23, 2024
Language: English
Credits: Produced by deaurider, Turgut Dincer and the Online
Distributed Proofreading Team at http://www.pgdp.net
(This
book was produced from images made available by the
HathiTrust Digital Library.)
*** START OF THE PROJECT GUTENBERG EBOOK GUNPOWDER
AND AMMUNITION, THEIR ORIGIN AND PROGRESS ***
Cover image created by transcriber and placed in the public domain.
GUNPOWDER AND
AMMUNITION
BY THE SAME AUTHOR
STRAY MILITARY PAPERS. With 2 Plates. 8vo,
7s. 6d
LUCIAN, THE SYRIAN SATIRIST. 8vo, 5s. net.
THE OUTLINES OF QUATERNIONS. Crown 8vo,
10s.
LONGMANS, GREEN, AND CO.
LONDON, NEW YORK, AND BOMBAY
GUNPOWDER AND
AMMUNITION
THEIR ORIGIN AND PROGRESS
BY
LIEUT.-COLONEL HENRY W. L. HIME
(LATE) ROYAL ARTILLERY
LONGMANS, GREEN, AND CO.
39 PATERNOSTER ROW, LONDON
NEW YORK AND BOMBAY
1904
All rights reserved
CONTENTS
PART I
THE ORIGIN OF GUNPOWDER
CHAP. PAGE
I. Introduction 3
II. Saltpetre 12
III. The Greeks 29
IV. Marcus Græcus 57
V. The Arabs 90
VI. The Hindus 105
VII. The Chinese 124
VIII. Friar Bacon 141
PART II
THE PROGRESS OF AMMUNITION
IX. Analytical Table of Ammunition 165
X. Hand Ammunition:—
Fire-Arrows and Fire-Pikes 168
Hand Grenades 169
XI. War Rockets 172
XII. Gunpowder 177
XIII. viShock Projectiles:—
Darts, &c. 199
Round Shot 200
Case 207
Shrapnel 208
XIV. Igneous Projectiles:—
Hot Shot 217
Incendiary Fireballs 217
Incendiary Shell 220
Carcasses 224
Explosive Fireballs 224
Explosive Shell 225
XV. Igniters:—
Hot Wires, Priming Powder, Matches, and Portfires 228
Tubes 230
Time Fuzes 231
Percussion and Concussion Fuzes 244
XVI. Signals 246
TABLES
TABLE PAGE
I. Methods of Refining Saltpetre 27
II. Greek Fires 32
III. Sea Fires 41
IV. Analytical Table of Ammunition 167
V. Price of English Powder at Various Times 184
VI. viiConnection between Size of Grain, Muzzle Velocity, and Pressure 195
VII. Composition of English Powder at Various Times 197
VIII. Composition of Foreign Powder at Various Times 198
IX. Price of Metals in 1375 and 1865 204
X.
Comparative Cost of One Round fired with Shot of Different Materials,
cir. 1375
205
XI.
Comparative Pressure on Bore when firing Shot of Different Materials,
cir. 1375
206
XII. Composition of Matches at Various Times 229
XIII. Composition of Time Fuzes at Various Times 243
XIV. Composition of Signal Rockets at Various Times 246
XV. Fixed Lights 246
XVI. Fireworks 247
Index 249
BOOKS OFTEN QUOTED
The following works are frequently quoted, and are only designated
by the author’s name. Thus, “Elliot,” ii. 75, means Sir H. M. Elliot’s
“Hist. of India, as told, &c. &c.,” vol. ii. p. 75.
Bacon, Roger, Opera quædam hactenus inedita, ed. by Professor
Brewer; Rolls Series, 1859.
Berthelot, M. P. E., La Chimie au Moyen Age, Paris, 1893.
Brackenbury, Lieut.-General Sir H., G.C.B., “Ancient Cannon in
Europe,” in vols. iv. and v. of Proceed. Roy. Artillery Institution,
Woolwich, 1865-6.
Elliot, Sir H. M., “Hist. of India, as told by its own Historians,” ed. by
Professor J. Dowson, M.R.A.S., London, 1867-77.
Jähns, Oberst-Lieut. M., Handbuch einer Geschichte des
Kriegswesens, Leipsig, 1880.
Napoleon III., Études sur le Passé et l’Avenir de l’Artillerie, Paris,
1846-71.
Nye, Master-Gunner N., “Art of Gunnery,” to which is added a
“Treatise on Artificial Fireworks” (separately paginated), London,
1647.
Reinaud (Professor) et Favé (Capitaine), Du Feu Grégeois, &c., Paris,
1845.
Romocki, S. J. von, Geschichte der Explosivstoffe, Hanover, 1895.
Whitehorne, P., “Certain Waies for the ordering of Souldiers in
Battelray,” London, 1560.
PART I
THE ORIGIN OF GUNPOWDER
CHAPTER I
INTRODUCTION
I
Much discussion has been caused in the past by the vagueness of the
word gunpowder. The following are the meanings which this and a
few other words bear in these pages:—
Explosion.—The sudden and violent generation, with a loud noise
and in a time inappreciable by the unaided senses, of a very
great volume of gas, by the combustion of a body occupying
a comparatively very small volume.
Progressive Combustion.—Combustion which takes place in a
time appreciable by the unaided senses, such as that of
rocket composition or a bit of paper.
Gunpowder.—A mixture of saltpetre, charcoal, and sulphur, which
explodes. The signs of its explosion are a bright flash, a loud
noise, and a large volume of smoke.
Incendiary (for “incendiary composition”).—A substance or
mixture which burns progressively, although fiercely, and is
hard to put out.
Machine always means an apparatus of the ballista type.
Cannon includes bombards, mortars, guns, &c.
Musket includes all hand firearms charged with gunpowder.
II
Of the many difficulties that beset the present inquiry, two
deserve special mention.
The first is the want of simple exactness in most early writers
when recording the facts from which we have to draw our
conclusions. At times their descriptions are so meagre that it is
difficult, if not impossible, to decide whether certain projectiles were
incendiary or explosive. At other times they abound in tropes and
figures of speech which amount to an unintentional suggestio falsi.
“The missiles spread themselves abroad like a cloud,” says a Spanish
Arab; “they roar like thunder; they flame like a furnace; they reduce
everything to ashes.”1 A projectile full of blazing Greek fire appeared
to Joinville to be of portentous bulk. It flew through the midnight sky
with thundering noise like a fiery dragon, followed by a long trail of
flame; and it illumined the whole camp as with the light of day.2
Even to approach the truth, we must prune such figures of rhetoric;
and this is a dangerous operation, for we may prune too much. The
only safeguard against these suggestive metaphors is to keep
steadily in view the distinctive peculiarities of incendiary and
explosive projectiles.
The incendiary shell was simply an envelope intended to convey
into the interior of a fort, ship, &c., a quantity of combustible matter,
which burned with such violence as to set fire to everything
inflammable that was near it. The primary object of the explosive
shell, on the other hand, was to blow up whatever it fell upon. It
might occasionally, by the intense heat generated by the explosion,3
set fire to its surroundings when inflammable; but this was a mere
incidental consequence of its action. Its aim and end was to explode.
When a musket or cannon was fired there was a bright flash, a
loud, momentary report, and a large volume of smoke.4 When an
incendiary missile was discharged from a machine there was no
flash, but little smoke, and the only sounds were the whizzing and
sputtering of the burning mixture and the creaking and groaning of
bolts, spars, ropes, &c.:—
“With grisly soune out goth the greté gonne.”5
An explosive missile made its way through the air with little
noise6 and less light:7 during its flight the blazing contents of the
incendiary shell doubtless gave out much light and made a
considerable noise, as described by many early writers. When an
explosive shell reached its object there was, sooner or later (if it
acted at all), an explosion, occasionally followed by a conflagration:
an incendiary shell produced a conflagration only.
The second difficulty arises from the change of meaning which
many technical words have undergone in the lapse of years.
The Arabic word barúd originally meant hail, was afterwards
applied to saltpetre, and finally came to signify gunpowder. Our own
word powder, which at first meant a fine, floury dust (pulvis), is
often used in the present day to designate the stringy nitrocelluloid,
cordite—smokeless powder. The Chinese word yo means gunpowder
now, although its first meaning was a drug or plant. For centuries
gunpowder was called kraut in Germany, and to this day it is called
kruid in Holland. The Danish krud has not long become obsolete.
The present Chinese word for firearm, huo p’áu, originally meant
a machine for throwing blazing incendiary matter. The Arabic word
bundúq at first meant a hazel-nut, secondly a clay-pellet the size of
a hazel-nut, thirdly a bullet, and finally a firearm.8 The Latin nochus,
a hazel-nut, is used, strange to say, to designate a smoke-ball by an
old German military writer, Konrad Kyeser, whose “Bellifortis” dates
from 1405.9 The word was also applied in Germany to bullets in
general, and more particularly to projectiles discharged by machines.
The word Artillery, both in France and England, originally meant
bows and arrows. In his original account of the battle of Cressy,
Froissart calls the apparatus and bolts of the Genoese crossbowmen
leur artillerie; while a few lines further on he speaks of the kanons of
the English.10 Ascham, writing in 1571, says: “Artillerie nowadays is
taken for two things: gunnes and bowes.”11 Selden reminds us that
gonne, our present gun, at first meant a machine of the ballista
type.12 It is used in this sense in “Kyng Alisaunder,” 3268, written
a.d. 1275-1300, and other metrical romances. Like the Arabic
bundúq, the word is occasionally applied to the projectile, as in the
“Avowing of Arthur,” st. 65. It is used in the modern sense, as
cannon, in the “Vision of Piers the Plowman,” Passus xxi, C text, 293,
a poem begun in 1362 and finally revised by its author in 1390; and
in all three meanings by Chaucer, in poems written during the last
quarter of the fourteenth century;—as a machine in the “Romaunt of
the Rose,” 4176, as a projectile in the “Legende of Good Women,”
637, and as a cannon in the “Hous of Fame,” 533.
“When the thing is perceived, the idea conceived,” says Professor
Whitney, “(men) find in the existing resources of speech the means
of its expression—a name which formerly belonged to something
else in some way akin to it; a combination of words,” &c.13 For
example, a word, W, which has always been the name of a thing, M,
is applied to some new thing, N, which has been devised for the
same use as M and answers the purpose better.14 W thus represents
both M and N for an indefinite time,15 until M eventually drops into
disuse and W comes to mean N and N only. The confusion
necessarily arising from the equivocal meaning of W during this
indefinite period, is entirely due, of course, to neglect of Horace’s
advice to coin new names for new things.16 Had a new name been
given to N from the first, no difficulty could possibly have ensued,
and our way would have been straight and clear. But as matters
have fallen out, not only have we to determine whether W means M
or N, whenever it is used during the transition period,17 but we have
to meet the arguments of those, never far off, who insist that
because W meant N finally, it must have meant N at some bygone
time when history and probability alike show that it meant M and M
only. Examples, enough and to spare, of such arguments will be met
with shortly.
In consequence of the change of meaning which many military
words have suffered, no translation of passages in foreign books
containing ambiguous words should be relied upon, if access to the
originals, or faithful copies of them, can be obtained. As an example
of the necessity for this precaution, let us compare a few sentences
relating to the siege of Jerusalem, a.d. 70, from the “Polychronicon”
of Higden (d. cir. 1363), Rolls Series, iv. 429 ff., with the translations
of them by Trevisa, 1385, and by the author of MS. Harl. No. 2261,
of a.d. 1432-50.
A
(1) Inde Vespasianus ictu arietis murum conturbat (Higden).
(2) Thanne Vaspacianus destourbed the wal with the stroke of an
engyne (Trevisa).
(3) Wherefore Vespasian troublede the walle soore with gunnes
and other engynes (MS. Harl.).
B
(1) Josephus tamen ardenti oleo superjecto omnia machinamenta
exussit (Higden).
(2) But Joseph threwe out brennynge oyle uppon alle her gynnes
and smoot all her gynnes (Trevisa).
(3) Then Josephus destroyede alle theire instruments in castenge
brennenge oyle on hit (MS. Harl.).
C
(1) Quo viso tanta vis telorum ex parte Titi proruit, ut unius de
sociis Josephi occipitium lapide percussum ultra tertium
stadium excuteretur (Higden).
(2) Whan that was i-seie there fil so gret strenthe of castynge and
of schot of Titus his side, that the noble knyght of oon of
Josephus his felowes was i-smyte of that place with a stoon
and flewe over the thrydde forlong (Trevisa).
(3) Titus perceyvenge that, sende furthe a sawte and schotte
gunnes to the walles in so much that the hynder parte of the
hedde of a man stondenge by Josephus was smyten by the
space of thre forlonges (MS. Harl.).
D
(1) Admotis tandem arietibus ad templum (Higden).
(2) At the laste the engynes were remeved toward the temple (Trevisa).
(3) Titus causede his gunners to schote at the Temple (MS. Harl.).
No suspicion rests upon either of these translators; yet, were the
original lost, a covert allusion to cannon might be discovered in
Trevisa’s translation of B and C, and the Harleian translation of A, C,
and D would be put forward as proof positive of their use.
III
The claims of the Greeks to the invention of gunpowder are
examined in Chap. III. Chap. IV. is an inquiry into the nature and
authorship of the Liber Ignium of Marcus Græcus. The claims of the
Arabs, Hindus, Chinese, and English are considered in Chaps. V.-VIII.
In Part II. the progress of Ammunition is very briefly traced from the
introduction of cannon to the introduction of breechloading arms.
As the book is addressed to the officers of the Army, who seldom
have a library at command, the authorities for the statements of
important facts are generally given at length. On all controversial
points, when a foreign authority is quoted the original18 is given as
well as the translation. I have endeavoured to acknowledge my
obligation in all cases where quotations have been borrowed from
others without verification.
The invention of gunpowder was impossible until the properties
of saltpetre had become known. We proceed, therefore, in the
following chapter to determine the approximate date of the
discovery of this salt.
CHAPTER II
SALTPETRE
The attention of the ancients was naturally attracted by the
efflorescences which form on certain stones, on walls, and in caves
and cellars; and the Hindus and nomad Arabs must have noticed the
deflagration of at least one of them when a fire was lit on it. These
efflorescences consist of various salts,—sulphate and carbonate of
soda, chloride of sodium, saltpetre, &c.—but they are so similar in
appearance and taste, the only two criteria known in primitive
times,19 that early observers succeeded in discriminating only one of
them, common salt, from the rest. So close, in fact, is the
resemblance between potash and soda, that their radical difference
was only finally established by Du Hamel in 1736. Common salt
received a distinctive name in remote times; all other salts were
grouped together under such vague generic names as nitrum,
natron, afro-nitron, &c.
No trace of saltpetre has hitherto been found anywhere before
the thirteenth century. The Greek alchemists of preceding centuries
are silent. There is no saltpetre in the earliest recipe we possess for
Greek fire, No. 26 of the Liber Ignium,20 ascribed to one Marcus
Græcus, either as given in the Paris MSS. of 1300, or in the Munich
MS. of 1438. It is true that the phrase sal coctus in this recipe has
been translated by saltpetre in M. Hœfer’s untrustworthy Histoire de
la Chimie, but as MM. Reinaud and Favé remark: “Rien n’autorise à
traduire ainsi; le sel ordinaire a été souvent employé dans les
artifices.”21 There is no instance in Latin, I believe, of saltpetre being
designated otherwise than by sal petræ (or petrosus), or by nitrum,
singly or in combination with some other word, as spuma nitri. The
substitution of sal petræ for sal coctus, in later editions of the recipe,
only shows that when the valuable properties of saltpetre became
known it was employed instead of common salt. The very fact of the
change having been made by most of the later alchemists, proves
that to them sal coctus did not mean sal petræ, but something else.
If sal coctus had meant sal petræ, what need was there for the
change? This change, however, was not universal. In the version of
recipe 26, given in the Livre de Canonnerie et Artifice de Feu,
published in Paris in 1561, but written long before by a fire-worker
well acquainted with saltpetre, we find: “prenez soufre vif, tarte,
farcocoly (sarcocolla), peghel (pitch), sarcosti (sal coctum), &c.”22
The word coquo (to boil or evaporate) was necessarily connected
with the preparation of common salt by evaporation,23 and coctus
would correctly distinguish evaporated or artificial salt from natural
or rock salt. In his “Natural History,” xxxi. 39 (7), Pliny tells us that
salt is found round the edges of certain lakes in Sicily which are
partially dried up in summer by the heat of the sun; while in Phrygia,
where much greater evaporation takes place (ubi largius coquitur), a
lake is dried up (and salt is deposited) to its very middle. Sal coctus
was salt recovered from salt water by natural or artificial heat, as
distinguished from natural, or rock salt, which was dug out of the
ground.24
The Arab alchemists before the thirteenth century are as silent as
the Greeks: nothing that can be identified with saltpetre is to be
found in their voluminous works. The evidence of Geber, so often
cited to prove that saltpetre was known to the Arabs in the ninth
century, has been stripped of all authority by M. Berthelot, who has
satisfactorily proved that there were two Gebers. The real Arab,
Jabir, says nothing of saltpetre, but he mentions a salve used by
naphtha-throwers25 as a safeguard against burns. The other Geber,
or pseudo-Jabir, was acquainted with saltpetre, as well he might be;
for he was a western who lived some time about the year 1300,26
and wrote a number of Latin works falsely purporting to be
translations from the Arabic of the real Jabir. All doubt about the
matter has been removed by M. Berthelot’s publication of the real
Jabir’s Arabic writings.27 It has been also suspected that the sal
Indicus of the Liber Sacerdotum, cir. tenth century,28 a salt again
mentioned in the Liber Secretorum of Bubacar, cir. 1000,29 means
saltpetre. Both these works are translations from the Arabic or
Persian,30 and sal Indicus is the literal translation of the Persian—
‫هندي‬ ‫نمك‬ (nimaki Hindi) = ‫سياه‬ ‫نمك‬ (nimaki siyah) = salt of
bitumen; a substance of the same family as the “salt of naphtha”
also mentioned by Bubacar.
There is no word for saltpetre in classical Sanskrit, sauverchala
being a generic term for natural salts, which corresponded to, and
was as comprehensive as the nitrum, spuma nitri, &c., of the West.
“Recent Sanskrit formulæ for the preparation of mineral acids
containing nitre, mention this salt under the name of soraka. This
word, however, is not met with in any Sanskrit dictionary, and is
evidently Sanskritised from the vernacular sora, a term of foreign
origin.”31 Both Professor H. H. Wilson and Professor M. Williams, in
their Sanskrit dictionaries, “erroneously render yavakshara as
saltpetre, as also does Colebrooke in his ‘Amara-kosha.’”32 The word
means impure carbonate of potash obtained by the incineration of
barley straw.33
At length, however, notwithstanding coarse scales and clumsy
apparatus, the want of all means of registering time and
temperature, and the absence of any general principle to guide them
in their researches, the alchemists succeeded in differentiating
certain natural salts from the rest, and among them saltpetre. The
Chinese were acquainted with it about the middle of the thirteenth
century.34 Abd Allah ibn al-Baythar, who died at Damascus in 1248,
tells us that the flower of the stone of Assos was called Chinese
snow by the Egyptian physicians and barūd (i.e. saltpetre) by the
(Arab) people of the West.35 Friar Bacon, whose De Secretis was
written before 1249, and Hassan er-Rammah who wrote 1275-95,
were thoroughly acquainted with the salt. A grand chemical
discovery had been made, and saltpetre became known from China
to Spain.
The Egyptians thought fit to call saltpetre “Chinese snow,” but
this does not justify the conclusion that the discovery was made by
the Chinese. Consider our own phrases “Jerusalem” artichoke,
“Welsh” onion, and “Turkey” cock. Jerusalem is a gardener’s
corruption of girasole, the Turkey came from America, and the home
of the Welsh onion is Siberia. The Persians called their native alkaline
salt jamadi Chini, and no one will suggest that this substance came
from China.
It is evident from the way in which it is mentioned by the
alchemists of the thirteenth century, and from their primitive
methods of refining it, that saltpetre was then in its infancy. Roger
Bacon speaks of it as one would speak of a substance recently
discovered and still little known—“that salt which is called saltpetre”
(illius salis qui sal petræ vocatur).36 Marcus Græcus thought it
necessary to explain what the word means, in his 14th recipe which
probably belongs to the latter years of the thirteenth century.37 The
methods of refining the salt given by Marcus and Hassan leave no
possible doubt that in their time it had but just come into use. It is
true that Bacon’s method was much superior, if the solution of his
steganogram given in Chap. viii. be accepted. But it would have
been past all explanation had the method of the greatest natural
philosopher of the age been found to be no better than that of an
Arabic druggist or a European fireworker.
As the matter is one of the greatest importance, the methods of
all three are given in full, together with that of Whitehorne, 1560.
The Waltham Abbey method is added, as a standard by which to
judge them. To admit of easy comparison, the corresponding
operations are marked with the same letter. The five methods are
summed up in Table I.
Waltham Abbey, 1860.
A. Preparation of grough from natural saltpetre.38
Natural saltpetre is dissolved in boiling water, the insoluble
impurities removed, and the solution evaporated by the sun or
artificial heat. The solid residue is grough saltpetre, and contains 1
to 10 per cent. of impurities, consisting of the chlorides of potassium
and sodium, sulphates of potash, soda, and calcium, vegetable
matter, sand, and moisture.
B. Boiling the solution of grough saltpetre.
The grough saltpetre is placed in an open copper with a false
bottom; water is added, and heat applied until the mixture boils at
110° C.
C. Removal of the insoluble impurities.
The scum which rises to the surface during this operation is
removed by ladles; the sand and heavy impurities fall upon the false
bottom, which is removed just before the mixture boils. The boiling
is continued until the scum ceases to rise.
D. Second boiling of the solution.
Cold water is added; the solution is boiled for a few minutes, and
then allowed to cool somewhat.
E. Filtration.
At 104.5° C. the mother liquid is transferred to a tank with holes
in its bottom, closed by filters.
F. Use of wood-ash, charcoal, &c.
If the impurities prevent the liquid from passing freely through
the filters, it is treated with glue, wood-ash, or, better, with a little
animal charcoal, which seizes on the impurities and rises to the top
as scum.
G. Crystallisation.
The mother liquid filters into the crystallising trough at 70.2° to
65.8° C.
H. Stirring the depositing solution.
The solution is kept in constant agitation by poles whilst cooling,
in order that it may deposit in minute crystals, called saltpetre flour.
Large crystals contain more or less of the impure mother liquid.
I. Washing and drying.
The agitation is discontinued at 25.8° C. and the mother liquid
drawn off. The flour is drained on an inclined plane, transferred to a
washing vat, where it is washed three times with cold water, and
then finally dried.
Whitehorne, 1560.
A. Preparation of grough from natural saltpetre.
On the bottom of a vessel pierced with “three or fower littell
holes” is placed a linen cloth, “or else the end of a broom, or some
straw.” A layer of nitrified earth, “a spanne thicknesse,” is laid on
this, and on the earth “three fingers’ thicknesse” of a mixture of
“two parts of unslacked lime and three of oke asshes, or other
asshes.... And so, putting one rewe” of saltpetre alternately with one
of the mixture, “you shall fill the tubbe ... within a spanne of (its
mouth), and the rest you will fill with water.” The water, on
percolating through the mass, drips into a brass cauldron which,
when two-thirds full, is boiled “till it come to one-third part or
thereabouts. And after take it off and put it to settell in a great
vessell,” when it is to be “clarified and from earthe and grosse
matter diligentlie purged.”
B. Boiling the solution of grough saltpetre.
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!
ebookultra.com

More Related Content

PDF
Even faster web sites 1st Edition Steve Souders
PDF
Javascript Web Applications Otx Alex Maccaw
PDF
Web_Development_with_Node_Express.pdf
PDF
Openstack Operations Guide 1st Edition Tom Fifield Diane Fleming
PDF
Java Network Programming Third Edition 3rd Edition Elliotte Rusty Harold
PDF
Node Up and Running Scalable Server Side Code with JavaScript 1st Edition Tom...
PDF
Node Up And Running Scalable Serverside Code With Javascript 1st Edition Tom ...
PDF
Client Server Web Apps with JavaScript and Java 1st Edition Casimir Saternos
Even faster web sites 1st Edition Steve Souders
Javascript Web Applications Otx Alex Maccaw
Web_Development_with_Node_Express.pdf
Openstack Operations Guide 1st Edition Tom Fifield Diane Fleming
Java Network Programming Third Edition 3rd Edition Elliotte Rusty Harold
Node Up and Running Scalable Server Side Code with JavaScript 1st Edition Tom...
Node Up And Running Scalable Serverside Code With Javascript 1st Edition Tom ...
Client Server Web Apps with JavaScript and Java 1st Edition Casimir Saternos

Similar to High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas (20)

PDF
Download full ebook of Learning Node Shelley Powers instant download pdf
PDF
Sustainable Web Development With Ruby On Rails Practical Tips For Building We...
PDF
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
PDF
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
PDF
Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...
PDF
Programming Windows Azure Programming The Microsoft Cloud 1st Edition Sriram ...
PDF
Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...
PDF
Programming Flex 2 Chafic Kazoun Joey Lott
PDF
Cloud Foundry the definitive guide develop deploy and scale First Edition Winn
PDF
OpenStack Operations Guide 1st Edition Tom Fifield
PDF
Java Network Programming Fourth Edition Harold Elliotte
PDF
AWS System Administration Best Practices for Sysadmins in the Amazon Cloud 1s...
PDF
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
PDF
AWS System Administration Best Practices for Sysadmins in the Amazon Cloud 1s...
PDF
Programming iOS 5 2nd Edition Matt Neuburg
PDF
C 7 0 in a Nutshell The Definitive Reference 7th Edition Joseph Albahari
PDF
Programming Ios 5 2nd Edition 2nd Early Release Draft Matt Neuburg
PDF
Client Server Web Apps with JavaScript and Java Rich Scalable and RESTful 1st...
PDF
RESTful Java With JAX RS 1st Edition Bill Burke
PDF
Java Complete Reference Fifth Edition
Download full ebook of Learning Node Shelley Powers instant download pdf
Sustainable Web Development With Ruby On Rails Practical Tips For Building We...
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...
Programming Windows Azure Programming The Microsoft Cloud 1st Edition Sriram ...
Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...
Programming Flex 2 Chafic Kazoun Joey Lott
Cloud Foundry the definitive guide develop deploy and scale First Edition Winn
OpenStack Operations Guide 1st Edition Tom Fifield
Java Network Programming Fourth Edition Harold Elliotte
AWS System Administration Best Practices for Sysadmins in the Amazon Cloud 1s...
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
AWS System Administration Best Practices for Sysadmins in the Amazon Cloud 1s...
Programming iOS 5 2nd Edition Matt Neuburg
C 7 0 in a Nutshell The Definitive Reference 7th Edition Joseph Albahari
Programming Ios 5 2nd Edition 2nd Early Release Draft Matt Neuburg
Client Server Web Apps with JavaScript and Java Rich Scalable and RESTful 1st...
RESTful Java With JAX RS 1st Edition Bill Burke
Java Complete Reference Fifth Edition
Ad

Recently uploaded (20)

PDF
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
PPTX
Renaissance Architecture: A Journey from Faith to Humanism
PDF
TR - Agricultural Crops Production NC III.pdf
PDF
VCE English Exam - Section C Student Revision Booklet
PDF
Complications of Minimal Access Surgery at WLH
PDF
Business Ethics Teaching Materials for college
PPTX
human mycosis Human fungal infections are called human mycosis..pptx
PDF
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 9 GLOBAL SUCCESS - CẢ NĂM - BÁM SÁT FORM Đ...
PDF
Chapter 2 Heredity, Prenatal Development, and Birth.pdf
PPTX
Pharmacology of Heart Failure /Pharmacotherapy of CHF
PDF
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
PDF
Abdominal Access Techniques with Prof. Dr. R K Mishra
PDF
102 student loan defaulters named and shamed – Is someone you know on the list?
PDF
O5-L3 Freight Transport Ops (International) V1.pdf
PDF
Pre independence Education in Inndia.pdf
PDF
01-Introduction-to-Information-Management.pdf
PPTX
Final Presentation General Medicine 03-08-2024.pptx
PDF
Supply Chain Operations Speaking Notes -ICLT Program
PPTX
school management -TNTEU- B.Ed., Semester II Unit 1.pptx
PPTX
master seminar digital applications in india
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
Renaissance Architecture: A Journey from Faith to Humanism
TR - Agricultural Crops Production NC III.pdf
VCE English Exam - Section C Student Revision Booklet
Complications of Minimal Access Surgery at WLH
Business Ethics Teaching Materials for college
human mycosis Human fungal infections are called human mycosis..pptx
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 9 GLOBAL SUCCESS - CẢ NĂM - BÁM SÁT FORM Đ...
Chapter 2 Heredity, Prenatal Development, and Birth.pdf
Pharmacology of Heart Failure /Pharmacotherapy of CHF
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
Abdominal Access Techniques with Prof. Dr. R K Mishra
102 student loan defaulters named and shamed – Is someone you know on the list?
O5-L3 Freight Transport Ops (International) V1.pdf
Pre independence Education in Inndia.pdf
01-Introduction-to-Information-Management.pdf
Final Presentation General Medicine 03-08-2024.pptx
Supply Chain Operations Speaking Notes -ICLT Program
school management -TNTEU- B.Ed., Semester II Unit 1.pptx
master seminar digital applications in india
Ad

High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas

  • 1. Visit https://ebookultra.com to download the full version and explore more ebooks High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas _____ Click the link below to download _____ https://ebookultra.com/download/high-performance- javascript-build-faster-web-application-interfaces-1st- edition-nicholas-c-zakas/ Explore and download more ebooks at ebookultra.com
  • 2. Here are some suggested products you might be interested in. Click the link to download Professional JavaScript for Web Developers 3rd Edition Nicholas C. Zakas https://ebookultra.com/download/professional-javascript-for-web- developers-3rd-edition-nicholas-c-zakas/ Professional JavaScript for web developers 2nd ed Edition Nicholas C. Zakas https://ebookultra.com/download/professional-javascript-for-web- developers-2nd-ed-edition-nicholas-c-zakas/ Learning Julia Build high performance applications for scientific computing 1st Edition Anshul Joshi https://ebookultra.com/download/learning-julia-build-high-performance- applications-for-scientific-computing-1st-edition-anshul-joshi/ Simulation Engineering Build Better Embedded Systems Faster 1st Edition Jim Ledin (Author) https://ebookultra.com/download/simulation-engineering-build-better- embedded-systems-faster-1st-edition-jim-ledin-author/
  • 3. Web Application Firewalls 1st Edition Chad Russell https://ebookultra.com/download/web-application-firewalls-1st-edition- chad-russell/ SproutCore Web Application Development 1st Edition Keating https://ebookultra.com/download/sproutcore-web-application- development-1st-edition-keating/ Web Application Defender s Cookbook Battling Hackers and Protecting Users 1st Edition Ryan C. Barnett https://ebookultra.com/download/web-application-defender-s-cookbook- battling-hackers-and-protecting-users-1st-edition-ryan-c-barnett/ Julia High performance 1st Edition Avik Sengupta https://ebookultra.com/download/julia-high-performance-1st-edition- avik-sengupta/ High Performance Plastics 2011 1st Edition Ismithers https://ebookultra.com/download/high-performance-plastics-2011-1st- edition-ismithers/
  • 5. High Performance JavaScript Build Faster Web Application Interfaces 1st Edition Nicholas C. Zakas Digital Instant Download Author(s): Nicholas C. Zakas ISBN(s): 9780596802790, 059680279X Edition: 1 File Details: PDF, 4.35 MB Year: 2010 Language: english
  • 10. High Performance JavaScript Nicholas C. Zakas Beijing • Cambridge • Farnham • Köln • Sebastopol • Taipei • Tokyo
  • 11. High Performance JavaScript by Nicholas C. Zakas Copyright © 2010 Yahoo!, Inc. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://my.safaribooksonline.com). For more information, contact our corporate/institutional sales department: (800) 998-9938 or corporate@oreilly.com. Editor: Mary E. Treseler Production Editor: Adam Zaremba Copyeditor: Genevieve d’Entremont Proofreader: Adam Zaremba Indexer: Fred Brown Cover Designer: Karen Montgomery Interior Designer: David Futato Illustrator: Robert Romano Printing History: March 2010: First Edition. Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly Media, Inc. High Performance JavaScript, the image of a short-eared owl, and related trade dress are trademarks of O’Reilly Media, Inc. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and O’Reilly Media, Inc. was aware of a trademark claim, the designations have been printed in caps or initial caps. While every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions, or for damages resulting from the use of the information con- tained herein. TM This book uses RepKover™, a durable and flexible lay-flat binding. ISBN: 978-0-596-80279-0 [M] 1268245906
  • 12. This book is dedicated to my family, Mom, Dad, and Greg, whose love and support have kept me going through the years.
  • 14. Table of Contents Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi 1. Loading and Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Script Positioning 2 Grouping Scripts 4 Nonblocking Scripts 5 Deferred Scripts 5 Dynamic Script Elements 6 XMLHttpRequest Script Injection 9 Recommended Nonblocking Pattern 10 Summary 14 2. Data Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Managing Scope 16 Scope Chains and Identifier Resolution 16 Identifier Resolution Performance 19 Scope Chain Augmentation 21 Dynamic Scopes 24 Closures, Scope, and Memory 24 Object Members 27 Prototypes 27 Prototype Chains 29 Nested Members 30 Caching Object Member Values 31 Summary 33 3. DOM Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 DOM in the Browser World 35 Inherently Slow 36 DOM Access and Modification 36 innerHTML Versus DOM methods 37 vii
  • 15. Cloning Nodes 41 HTML Collections 42 Walking the DOM 46 Repaints and Reflows 50 When Does a Reflow Happen? 51 Queuing and Flushing Render Tree Changes 51 Minimizing Repaints and Reflows 52 Caching Layout Information 56 Take Elements Out of the Flow for Animations 56 IE and :hover 57 Event Delegation 57 Summary 59 4. Algorithms and Flow Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Loops 61 Types of Loops 61 Loop Performance 63 Function-Based Iteration 67 Conditionals 68 if-else Versus switch 68 Optimizing if-else 70 Lookup Tables 72 Recursion 73 Call Stack Limits 74 Recursion Patterns 75 Iteration 76 Memoization 77 Summary 79 5. Strings and Regular Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 String Concatenation 81 Plus (+) and Plus-Equals (+=) Operators 82 Array Joining 84 String.prototype.concat 86 Regular Expression Optimization 87 How Regular Expressions Work 88 Understanding Backtracking 89 Runaway Backtracking 91 A Note on Benchmarking 96 More Ways to Improve Regular Expression Efficiency 96 When Not to Use Regular Expressions 99 String Trimming 99 Trimming with Regular Expressions 99 viii | Table of Contents
  • 16. Trimming Without Regular Expressions 102 A Hybrid Solution 103 Summary 104 6. Responsive Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 The Browser UI Thread 107 Browser Limits 109 How Long Is Too Long? 110 Yielding with Timers 111 Timer Basics 112 Timer Precision 114 Array Processing with Timers 114 Splitting Up Tasks 116 Timed Code 118 Timers and Performance 119 Web Workers 120 Worker Environment 120 Worker Communication 121 Loading External Files 122 Practical Uses 122 Summary 124 7. Ajax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 Data Transmission 125 Requesting Data 125 Sending Data 131 Data Formats 134 XML 134 JSON 137 HTML 141 Custom Formatting 142 Data Format Conclusions 144 Ajax Performance Guidelines 145 Cache Data 145 Know the Limitations of Your Ajax Library 148 Summary 149 8. Programming Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 Avoid Double Evaluation 151 Use Object/Array Literals 153 Don’t Repeat Work 154 Lazy Loading 154 Conditional Advance Loading 156 Table of Contents | ix
  • 17. Use the Fast Parts 156 Bitwise Operators 156 Native Methods 159 Summary 161 9. Building and Deploying High-Performance JavaScript Applications . . . . . . . . . . . 163 Apache Ant 163 Combining JavaScript Files 165 Preprocessing JavaScript Files 166 JavaScript Minification 168 Buildtime Versus Runtime Build Processes 170 JavaScript Compression 170 Caching JavaScript Files 171 Working Around Caching Issues 172 Using a Content Delivery Network 173 Deploying JavaScript Resources 173 Agile JavaScript Build Process 174 Summary 175 10. Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 JavaScript Profiling 178 YUI Profiler 179 Anonymous Functions 182 Firebug 183 Console Panel Profiler 183 Console API 184 Net Panel 185 Internet Explorer Developer Tools 186 Safari Web Inspector 188 Profiles Panel 189 Resources Panel 191 Chrome Developer Tools 192 Script Blocking 193 Page Speed 194 Fiddler 196 YSlow 198 dynaTrace Ajax Edition 199 Summary 202 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 x | Table of Contents
  • 18. Preface When JavaScript was first introduced as part of Netscape Navigator in 1996, perform- ance wasn’t that important. The Internet was in its infancy and it was, in all ways, slow. From dial-up connections to underpowered home computers, surfing the Web was more often a lesson in patience than anything else. Users expected to wait for web pages to load, and when the page successfully loaded, it was a cause for celebration. JavaScript’s original goal was to improve the user experience of web pages. Instead of going back to the server for simple tasks such as form validation, JavaScript allowed embedding of this functionality directly in the page. Doing so saved a rather long trip back to the server. Imagine the frustration of filling out a long form, submitting it, and then waiting 30–60 seconds just to get a message back indicating that you had filled in a single field incorrectly. JavaScript can rightfully be credited with saving early Internet users a lot of time. The Internet Evolves Over the decade that followed, computers and the Internet continued to evolve. To start, both got much faster. The rapid speed-up of microprocessors, the availability of cheap memory, and the appearance of fiber optic connections pushed the Internet into a new age. With high-speed connections more available than ever, web pages started becoming heavier, embedding more information and multimedia. The Web had changed from a fairly bland landscape of interlinked documents into one filled with different designs and interfaces. Everything changed, that is, except JavaScript. What previously was used to save server roundtrips started to become more ubiquitous. Where there were once dozens of lines of JavaScript code were now hundreds, and eventually thousands. The introduction of Internet Explorer 4 and dynamic HTML (the ability to change aspects of the page without a reload) ensured that the amount of JavaScript on pages would only increase over time. The last major step in the evolution of browsers was the introduction of the Document Object Model (DOM), a unified approach to dynamic HTML that was adopted by Internet Explorer 5, Netscape 6, and Opera. This was closely followed by the xi
  • 19. standardization of JavaScript into ECMA-262, third edition. With all browsers sup- porting the DOM and (more or less) the same version of JavaScript, a web application platform was born. Despite this huge leap forward, with a common API against which to write JavaScript, the JavaScript engines in charge of executing that code remained mostly unchanged. Why Optimization Is Necessary The JavaScript engines that supported web pages with a few dozen lines of JavaScript in 1996 are the same ones running web applications with thousands of lines of Java- Script today. In many ways, the browsers fell behind in their management of the lan- guage and in doing the groundwork so that JavaScript could succeed at a large scale. This became evident with Internet Explorer 6, which was heralded for its stability and speed when it was first released but later reviled as a horrible web application platform because of its bugs and slowness. In reality, IE 6 hadn’t gotten any slower; it was just being asked to do more than it had previously. The types of early web applications being created when IE 6 was introduced in 2001 were much lighter and used much less JavaScript than those created in 2005. The difference in the amount of JavaScript code became clear as the IE 6 JavaScript engine struggled to keep up due to its static garbage-collection routine. The engine looked for a fixed number of objects in memory to determine when to collect garbage. Earlier web application developers had run into this threshold infrequently, but with more JavaScript code comes more objects, and complex web applications began to hit this threshold quite often. The problem became clear: JavaScript developers and web applications had evolved while the JavaScript engines had not. Although other browsers had more logical garbage collection routines, and somewhat better runtime performance, most still used a JavaScript interpreter to execute code. Code interpretation is inherently slower than compilation since there’s a translation process between the code and the computer instructions that must be run. No matter how smart and optimized interpreters get, they always incur a performance penalty. Compilers are filled with all kinds of optimizations that allow developers to write code in whatever way they want without worrying whether it’s optimal. The compiler can determine, based on lexical analysis, what the code is attempting to do and then opti- mize it by producing the fastest-running machine code to complete the task. Interpret- ers have few such optimizations, which frequently means that code is executed exactly as it is written. In effect, JavaScript forces the developer to perform the optimizations that a compiler would normally handle in other languages. xii | Preface
  • 20. Next-Generation JavaScript Engines In 2008, JavaScript engines got their first big performance boost. Google introduced their brand-new browser called Chrome. Chrome was the first browser released with an optimizing JavaScript engine, codenamed V8. The V8 JavaScript engine is a just-in- time (JIT) compilation engine for JavaScript, which produces machine code from Java- Script code and then executes it. The resulting experience is blazingly fast JavaScript execution. Other browsers soon followed suit with their own optimizing JavaScript engines. Safari 4 features the Squirrel Fish Extreme (also called Nitro) JIT JavaScript engine, and Fire- fox 3.5 includes the TraceMonkey engine, which optimizes frequently executed code paths. With these newer JavaScript engines, optimizations are being done at the compiler- level, where they should be done. Someday, developers may be completely free of worry about performance optimizations in their code. That day, however, is still not here. Performance Is Still a Concern Despite advancements in core JavaScript execution time, there are still aspects of Java- Script that these new engines don’t handle. Delays caused by network latency and operations affecting the appearance of the page are areas that have yet to be adequately optimized by browsers. While simple optimizations such as function inlining, code folding, and string concatenation algorithms are easily optimized in compilers, the dy- namic and multifaceted structure of web applications means that these optimizations solve only part of the performance problem. Though newer JavaScript engines have given us a glimpse into the future of a much faster Internet, the performance lessons of today will continue to be relevant and im- portant for the foreseeable future. The techniques and approaches taught in this book address many different aspects of JavaScript, covering execution time, downloading, interaction with the DOM, page life cycle, and more. Of these topics only a small subset, those related to core (ECMAScript) performance, could be rendered irrelevant by advances in JavaScript engines, but that has yet to happen. The other topics cover ground where faster JavaScript engines won’t help: DOM in- teraction, network latency, blocking and concurrent downloading of JavaScript, and more. These topics will not only continue to be relevant, but will become areas of further focus and research as low-level JavaScript execution time continues to improve. Preface | xiii
  • 21. How This Book Is Organized The chapters in this book are organized based on a normal JavaScript development life cycle. This begins, in Chapter 1, with the most optimal ways to load JavaScript onto the page. Chapter 2 through Chapter 8 focus on specific programming techniques to help your JavaScript code run as quickly as possible. Chapter 9 discusses the best ways to build and deploy your JavaScript files to a production environment, and Chap- ter 10 covers performance tools that can help you identify further issues once the code is deployed. Five of the chapters were written by contributing authors: • Chapter 3, DOM Scripting, by Stoyan Stefanov • Chapter 5, Strings and Regular Expressions, by Steven Levithan • Chapter 7, Ajax, by Ross Harmes • Chapter 9, Building and Deploying High-Performance JavaScript Applications, by Julien Lecomte • Chapter 10, Tools, by Matt Sweeney Each of these authors is an accomplished web developer who has made important contributions to the web development community as a whole. Their names appear on the opening page of their respective chapters to more easily identify their work. JavaScript Loading Chapter 1, Loading and Execution, starts with the basics of JavaScript: getting code onto the page. JavaScript performance really begins with getting the code onto a page in the most efficient way possible. This chapter focuses on the performance problems associated with loading JavaScript code and presents several ways to mitigate the effects. Coding Technique A large source of performance problems in JavaScript is poorly written code that uses inefficient algorithms or utilities. The following seven chapters focus on identifying problem code and presenting faster alternatives that accomplish the same task. Chapter 2, Data Access, focuses on how JavaScript stores and accesses data within a script. Where you store data is just as important as what you store, and this chapter explains how concepts such as the scope chain and prototype chain can affect your overall script performance. Stoyan Stefanov, who is well versed in the internal workings of a web browser, wrote Chapter 3, DOM Scripting. Stoyan explains that DOM interaction is slower than other parts of JavaScript because of the way it is implemented. He covers all aspects of the DOM, including a description of how repaint and reflow can slow down your code. xiv | Preface
  • 22. Chapter 4, Algorithms and Flow Control, explains how common programming para- digms such as loops and recursion can work against you when it comes to runtime performance. Optimization techniques such as memoization are discussed, as are browser JavaScript runtime limitations. Many web applications perform complex string operations in JavaScript, which is why string expert Steven Levithan covers the topic in Chapter 5, Strings and Regular Ex- pressions. Web developers have been fighting poor string-handling performance in browsers for years, and Steven explains why some operations are slow and how to work around them. Chapter 6, Responsive Interfaces, puts the spotlight firmly on the user experience. Java- Script can cause the browser to freeze as it executes, leaving users extremely frustrated. This chapter discusses several techniques to ensure that the user interface remains re- sponsive at all times. In Chapter 7, Ajax, Ross Harmes discusses the best ways to achieve fast client-server communication in JavaScript. Ross covers how different data formats can affect Ajax performance and why XMLHttpRequest isn’t always the best choice. Chapter 8, Programming Practices, is a collection of best practices that are unique to JavaScript programming. Deployment Once JavaScript code is written and tested, it’s time to make the changes available to everyone. However, you shouldn’t just push out your raw source files for use in pro- duction. Julien Lecomte shows how to improve the performance of your JavaScript during deployment in Chapter 9, Building and Deploying High-Performance JavaScript Applications. Julien discusses using a build system to automatically minify files and using HTTP compression to deliver them to the browser. Testing When all of your JavaScript code is deployed, the next step is to begin performance testing. Matt Sweeney covers testing methodology and tools in Chapter 10, Tools. He discusses how to use JavaScript to measure performance and also describes common tools both for evaluating JavaScript runtime performance and for uncovering perform- ance problems through HTTP sniffing. Who This Book Is For This book is aimed at web developers with an intermediate-to-advanced understanding ofJavaScriptwhoarelookingtoimprovetheperformanceofwebapplicationinterfaces. Preface | xv
  • 23. Conventions Used in This Book The following typographical conventions are used in this book: Italic Indicates new terms, URLs, email addresses, filenames, and file extensions. Constant width Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords. Constant width bold Shows commands or other text that should be typed literally by the user. Constant width italic Shows text that should be replaced with user-supplied values or by values deter- mined by context. This icon signifies a tip, suggestion, or general note. This icon indicates a warning or caution. Using Code Examples This book is here to help you get your job done. In general, you may use the code in this book in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing a CD-ROM of examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission. We appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “High Performance JavaScript, by Nicholas C. Zakas. Copyright 2010 Yahoo!, Inc., 978-0-596-80279-0.” If you feel your use of code examples falls outside fair use or the permission given here, feel free to contact us at permissions@oreilly.com. xvi | Preface
  • 24. Safari® Books Online Safari Books Online is an on-demand digital library that lets you easily search over 7,500 technology and creative reference books and videos to find the answers you need quickly. Withasubscription,youcanreadanypageandwatchanyvideofromourlibraryonline. Read books on your cell phone and mobile devices. Access new titles before they are available for print, and get exclusive access to manuscripts in development and post feedback for the authors. Copy and paste code samples, organize your favorites, down- load chapters, bookmark key sections, create notes, print out pages, and benefit from tons of other time-saving features. O’Reilly Media has uploaded this book to the Safari Books Online service. To have full digital access to this book and others on similar topics from O’Reilly and other pub- lishers, sign up for free at http://my.safaribooksonline.com. How to Contact Us Please address comments and questions concerning this book to the publisher: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 800-998-9938 (in the United States or Canada) 707-829-0515 (international or local) 707-829-0104 (fax) We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at: http://www.oreilly.com/catalog/9780596802790 To comment or ask technical questions about this book, send email to: bookquestions@oreilly.com For more information about our books, conferences, Resource Centers, and the O’Reilly Network, see our website at: http://www.oreilly.com Preface | xvii
  • 25. Acknowledgments First and foremost, I’d like to thank all of the contributing authors: Matt Sweeney, Stoyan Stefanov, Stephen Levithan, Ross Harmes, and Julien Lecomte. Having their combined expertise and knowledge as part of this book made the process more exciting and the end result more compelling. Thanks to all of the performance gurus of the world that I’ve had the opportunity to meet and interact with, especially Steve Souders, Tenni Theurer, and Nicole Sullivan. You three helped expand my horizons when it comes to web performance, and I’m incredibly grateful for that. A big thanks to everyone who reviewed the book prior to publication, including Ryan Grove, Oliver Hunt, Matthew Russell, Ted Roden, Remy Sharp, and Venkateswaran Udayasankar. Their early feedback was invaluable in preparing the book for production. And a huge thanks to everyone at O’Reilly and Yahoo! that made this book possible. I’ve wanted to write a book for Yahoo! ever since I joined the company in 2006, and Yahoo! Press was a great way to make this happen. xviii | Preface
  • 26. CHAPTER 1 Loading and Execution JavaScript performance in the browser is arguably the most important usability issue facingdevelopers.TheproblemiscomplexbecauseoftheblockingnatureofJavaScript, which is to say that nothing else can happen while JavaScript code is being executed. In fact, most browsers use a single process for both user interface (UI) updates and JavaScript execution, so only one can happen at any given moment in time. The longer JavaScript takes to execute, the longer it takes before the browser is free to respond to user input. On a basic level, this means that the very presence of a <script> tag is enough to make the page wait for the script to be parsed and executed. Whether the actual JavaScript code is inline with the tag or included in an external file is irrelevant; the page download and rendering must stop and wait for the script to complete before proceeding. This is a necessary part of the page’s life cycle because the script may cause changes to the page while executing. The typical example is using document.write() in the middle of a page (as often used by advertisements). For example: <html> <head> <title>Script Example</title> </head> <body> <p> <script type="text/javascript"> document.write("The date is " + (new Date()).toDateString()); </script> </p> </body> </html> When the browser encounters a <script> tag, as in this HTML page, there is no way of knowing whether the JavaScript will insert content into the <p>, introduce additional elements, or perhaps even close the tag. Therefore, the browser stops processing the page as it comes in, executes the JavaScript code, then continues parsing and rendering the page. The same takes place for JavaScript loaded using thesrc attribute; the browser must first download the code from the external file, which takes time, and then parse 1
  • 27. and execute the code. Page rendering and user interaction are completely blocked dur- ing this time. The two leading sources of information on JavaScript affecting page download performance are the Yahoo! Exceptional Performance team (http://developer.yahoo.com/performance/) and Steve Souders, author of High Performance Web Sites (O’Reilly) and Even Faster Web Sites (O’Re- illy). This chapter is heavily influenced by their combined research. Script Positioning The HTML 4 specification indicates that a <script> tag may be placed inside of a <head> or <body> tag in an HTML document and may appear any number of times within each. Traditionally, <script> tags that are used to load external JavaScript files have appeared in the <head>, along with <link> tags to load external CSS files and other metainformation about the page. The theory was that it’s best to keep as many style and behavior dependencies together, loading them first so that the page will come in looking and behaving correctly. For example: <html> <head> <title>Script Example</title> <-- Example of inefficient script positioning --> <script type="text/javascript" src="file1.js"></script> <script type="text/javascript" src="file2.js"></script> <script type="text/javascript" src="file3.js"></script> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <p>Hello world!</p> </body> </html> Though this code seems innocuous, it actually has a severe performance issue: there are three JavaScript files being loaded in the <head>. Since each <script> tag blocks the page from continuing to render until it has fully downloaded and executed the Java- Script code, the perceived performance of this page will suffer. Keep in mind that browsers don’t start rendering anything on the page until the opening <body> tag is encountered. Putting scripts at the top of the page in this way typically leads to a no- ticeable delay, often in the form of a blank white page, before the user can even begin reading or otherwise interacting with the page. To get a good understanding of how this occurs, it’s useful to look at a waterfall diagram showing when each resource is downloaded. Figure 1-1 shows when each script and the stylesheet file get downloaded as the page is loading. Figure 1-1 shows an interesting pattern. The first JavaScript file begins to download and blocks any of the other files from downloading in the meantime. Further, there is 2 | Chapter 1: Loading and Execution
  • 28. a delay between the time at which file1.js is completely downloaded and the time at which file2.js begins to download. That space is the time it takes for the code contained in file1.js to fully execute. Each file must wait until the previous one has been down- loaded and executed before the next download can begin. In the meantime, the user is met with a blank screen as the files are being downloaded one at a time. This is the behavior of most major browsers today. Internet Explorer 8, Firefox 3.5, Safari 4, and Chrome 2 all allow parallel downloads of JavaScript files. This is good news because the <script> tags don’t necessarily block other <script> tags from downloading external resources. Unfortunately, JavaScript downloadsstillblockdownloadingofotherresources,suchasimages.Andeventhough downloading a script doesn’t block other scripts from downloading, the page must still wait for the JavaScript code to be downloaded and executed before continuing. So while the latest browsers have improved performance by allowing parallel downloads, the problem hasn’t been completely solved. Script blocking still remains a problem. Because scripts block downloading of all resource types on the page, it’s recommended to place all <script> tags as close to the bottom of the <body> tag as possible so as not to affect the download of the entire page. For example: <html> <head> <title>Script Example</title> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <p>Hello world!</p> <-- Example of recommended script positioning --> <script type="text/javascript" src="file1.js"></script> <script type="text/javascript" src="file2.js"></script> <script type="text/javascript" src="file3.js"></script> </body> </html> This code represents the recommended position for <script> tags in an HTML file. Even though the script downloads will block one another, the rest of the page has Figure 1-1. JavaScript code execution blocks other file downloads Script Positioning | 3
  • 29. already been downloaded and displayed to the user so that the entire page isn’t per- ceived as slow. This is the Yahoo! Exceptional Performance team’s first rule about JavaScript: put scripts at the bottom. Grouping Scripts Since each <script> tag blocks the page from rendering during initial download, it’s helpful to limit the total number of <script> tags contained in the page. This applies to both inline scripts as well as those in external files. Every time a <script> tag is encountered during the parsing of an HTML page, there is going to be a delay while the code is executed; minimizing these delays improves the overall performance of the page. Steve Souders has also found that an inline script placed after a <link> tag referencing an external stylesheet caused the browser to block while waiting for the stylesheet to download. This is done to ensure that the inline script will have the most correct style information with which to work. Souders recommends never putting an inline script after a <link> tag for this reason. The problem is slightly different when dealing with external JavaScript files. Each HTTP request brings with it additional performance overhead, so downloading one single 100 KB file will be faster than downloading four 25 KB files. To that end, it’s helpful to limit the number of external script files that your page references. Typically, a large website or web application will have several required JavaScript files. You can minimize the performance impact by concatenating these files together into a single file and then calling that single file with a single <script> tag. The concatenation can happen offline using a build tool (discussed in Chapter 9) or in real-time using a tool such as the Yahoo! combo handler. Yahoo! created the combo handler for use in distributing the Yahoo! User Interface (YUI) library files through their Content Delivery Network (CDN). Any website can pull in any number of YUI files by using a combo-handled URL and specifying the files to include. For example, this URL includes two files: http://yui.yahooapis.com/combo ?2.7.0/build/yahoo/yahoo-min.js&2.7.0/build/event/event-min.js. This URL loads the 2.7.0 versions of the yahoo-min.js and event-min.js files. These files exist separately on the server but are combined when this URL is requested. Instead of using two <script> tags (one to load each file), a single <script> tag can be used to load both: 4 | Chapter 1: Loading and Execution
  • 30. <html> <head> <title>Script Example</title> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <p>Hello world!</p> <-- Example of recommended script positioning --> <script type="text/javascript" src=" http://yui.yahooapis.com/combo?2.7.0/build/yahoo/yahoo-min.js& 2.7.0/build/event/event-min.js "></script> </body> </html> This code has a single <script> tag at the bottom of the page that loads multiple Java- Script files, showing the best practice for including external JavaScript on an HTML page. Nonblocking Scripts JavaScript’s tendency to block browser processes, both HTTP requests and UI updates, is the most notable performance issue facing developers. Keeping JavaScript files small and limiting the number of HTTP requests are only the first steps in creating a respon- sive web application. The richer the functionality an application requires, the more JavaScript code is required, and so keeping source code small isn’t always an option. Limiting yourself to downloading a single large JavaScript file will only result in locking the browser out for a long period of time, despite it being just one HTTP request. To get around this situation, you need to incrementally add more JavaScript to the page in a way that doesn’t block the browser. The secret to nonblocking scripts is to load the JavaScript source code after the page has finished loading. In technical terms, this means downloading the code after the window’s load event has been fired. There are a few techniques for achieving this result. Deferred Scripts HTML 4 defines an additional attribute for the <script> tag called defer. The defer attribute indicates that the script contained within the element is not going to modify the DOM and therefore execution can be safely deferred until a later point in time. The defer attribute is supported only in Internet Explorer 4+ and Firefox 3.5+, making it less than ideal for a generic cross-browser solution. In other browsers, the defer at- tribute is simply ignored and so the <script> tag is treated in the default (blocking) manner. Still, this solution is useful if your target browsers support it. The following is an example usage: <script type="text/javascript" src="file1.js" defer></script> Nonblocking Scripts | 5
  • 31. A <script> tag with defer may be placed anywhere in the document. The JavaScript file will begin downloading at the point that the <script> tag is parsed, but the code will not be executed until the DOM has been completely loaded (before the onload event handler is called). When a deferred JavaScript file is downloaded, it doesn’t block the browser’s other processes, and so these files can be downloaded in parallel with others on the page. Any <script> element marked with defer will not execute until after the DOM has been completely loaded; this holds true for inline scripts as well as for external script files. The following simple page demonstrates how the defer attribute alters the behavior of scripts: <html> <head> <title>Script Defer Example</title> </head> <body> <script defer> alert("defer"); </script> <script> alert("script"); </script> <script> window.onload = function(){ alert("load"); }; </script> </body> </html> This code displays three alerts as the page is being processed. In browsers that don’t support defer, the order of the alerts is “defer”, “script”, and “load”. In browsers that support defer, the order of the alerts is “script”, “defer”, and “load”. Note that the deferred <script> element isn’t executed until after the second but is executed before the onload event handler is called. If your target browsers include only Internet Explorer and Firefox 3.5, then deferring scripts in this manner can be helpful. If you have a larger cross-section of browsers to support, there are other solutions that work in a more consistent manner. Dynamic Script Elements The Document Object Model (DOM) allows you to dynamically create almost any part of an HTML document using JavaScript. At its root, the <script> element isn’t any different than any other element on a page: references can be retrieved through the DOM, and they can be moved, removed from the document, and even created. A new <script> element can be created very easily using standard DOM methods: 6 | Chapter 1: Loading and Execution
  • 32. var script = document.createElement("script"); script.type = "text/javascript"; script.src = "file1.js"; document.getElementsByTagName("head")[0].appendChild(script); This new <script> element loads the source file file1.js. The file begins downloading as soon as the element is added to the page. The important thing about this technique is that the file is downloaded and executed without blocking other page processes, regardless of where the download is initiated. You can even place this code in the <head> of a document without affecting the rest of the page (aside from the one HTTP connection that is used to download the file). It’s generally safer to add new <script> nodes to the <head> element instead of the <body>, especially if this code is executing during page load. Internet Explorer may experience an “operation aborted” error if all of the <body> contents have not yet been loaded.* When a file is downloaded using a dynamic script node, the retrieved code is typically executed immediately (except in Firefox and Opera, which will wait until any previous dynamic script nodes have executed). This works well when the script is self-executing but can be problematic if the code contains only interfaces to be used by other scripts on the page. In that case, you need to track when the code has been fully downloaded and is ready for use. This is accomplished using events that are fired by the dynamic <script> node. Firefox, Opera, Chrome, and Safari 3+ all fire a load event when the src of a <script> element has been retrieved. You can therefore be notified when the script is ready by listening for this event: var script = document.createElement("script") script.type = "text/javascript"; //Firefox, Opera, Chrome, Safari 3+ script.onload = function(){ alert("Script loaded!"); }; script.src = "file1.js"; document.getElementsByTagName("head")[0].appendChild(script); Internet Explorer supports an alternate implementation that fires a readystatechange event. There is a readyState property on the <script> element that is changed at various times during the download of an external file. There are five possible values for ready State: * See “The dreaded operation aborted error” at http://www.nczonline.net/blog/2008/03/17/the -dreaded-operation-aborted-error/ for a more in-depth discussion of this issue. Nonblocking Scripts | 7
  • 33. "uninitialized" The default state "loading" Download has begun "loaded" Download has completed "interactive" Data is completely downloaded but isn’t fully available "complete" All data is ready to be used Microsoft’s documentation for readyState and each of the possible values seems to indicate that not all states will be used during the lifetime of the <script> element, but there is no indication as to which will always be used. In practice, the two states of most interest are "loaded" and "complete". Internet Explorer is inconsistent with which of these two readyState values indicates the final state, as sometimes the <script> element will reach the "loaded" state but never reach "complete" whereas other times "com plete" will be reached without "loaded" ever having been used. The safest way to use the readystatechange event is to check for both of these states and remove the event handler when either one occurs (to ensure the event isn’t handled twice): var script = document.createElement("script") script.type = "text/javascript"; //Internet Explorer script.onreadystatechange = function(){ if (script.readyState == "loaded" || script.readyState == "complete"){ script.onreadystatechange = null; alert("Script loaded."); } }; script.src = "file1.js"; document.getElementsByTagName("head")[0].appendChild(script); In most cases, you’ll want to use a single approach to dynamically load JavaScript files. The following function encapsulates both the standard and IE-specific functionality: function loadScript(url, callback){ var script = document.createElement("script") script.type = "text/javascript"; if (script.readyState){ //IE script.onreadystatechange = function(){ if (script.readyState == "loaded" || script.readyState == "complete"){ script.onreadystatechange = null; callback(); } }; 8 | Chapter 1: Loading and Execution
  • 34. } else { //Others script.onload = function(){ callback(); }; } script.src = url; document.getElementsByTagName("head")[0].appendChild(script); } This function accepts two arguments: the URL of the JavaScript file to retrieve and a callback function to execute when the JavaScript has been fully loaded. Feature detec- tion is used to determine which event handler should monitor the script’s progress. The last step is to assign the src property and add the <script> element to the page. The loadScript() function is used as follows: loadScript("file1.js", function(){ alert("File is loaded!"); }); You can dynamically load as many JavaScript files as necessary on a page, but make sure you consider the order in which files must be loaded. Of all the major browsers, only Firefox and Opera guarantee that the order of script execution will remain the same as you specify. Other browsers will download and execute the various code files in the order in which they are returned from the server. You can guarantee the order by chaining the downloads together, such as: loadScript("file1.js", function(){ loadScript("file2.js", function(){ loadScript("file3.js", function(){ alert("All files are loaded!"); }); }); }); This code waits to begin loading file2.js until file1.js is available and also waits to download file3.js until file2.js is available. Though possible, this approach can get a little bit difficult to manage if there are multiple files to download and execute. If the order of multiple files is important, the preferred approach is to concatenate the files into a single file where each part is in the correct order. That single file can then be downloaded to retrieve all of the code at once (since this is happening asynchro- nously, there’s no penalty for having a larger file). Dynamic script loading is the most frequently used pattern for nonblocking JavaScript downloads due to its cross-browser compatibility and ease of use. XMLHttpRequest Script Injection Another approach to nonblocking scripts is to retrieve the JavaScript code using an XMLHttpRequest (XHR) object and then inject the script into the page. This technique Nonblocking Scripts | 9
  • 35. involves creating an XHR object, downloading the JavaScript file, then injecting the JavaScript code into the page using a dynamic <script> element. Here’s a simple example: var xhr = new XMLHttpRequest(); xhr.open("get", "file1.js", true); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ var script = document.createElement("script"); script.type = "text/javascript"; script.text = xhr.responseText; document.body.appendChild(script); } } }; xhr.send(null); This code sends a GET request for the file file1.js. The onreadystatechange event handler checks for a readyState of 4 and then verifies that the HTTP status code is valid (any- thing in the 200 range means a valid response, and 304 means a cached response). If a valid response has been received, then a new <script> element is created and its text property is assigned to the responseText received from the server. Doing so essentially creates a <script> element with inline code. Once the new <script> element is added to the document, the code is executed and is ready to use. The primary advantage of this approach is that you can download the JavaScript code without executing it immediately. Since the code is being returned outside of a <script> tag, it won’t automatically be executed upon download, allowing you to defer its execution until you’re ready. Another advantage is that the same code works in all modern browsers without exception cases. The primary limitation of this approach is that the JavaScript file must be located on the same domain as the page requesting it, which makes downloading from CDNs impossible. For this reason, XHR script injection typically isn’t used on large-scale web applications. Recommended Nonblocking Pattern The recommend approach to loading a significant amount of JavaScript onto a page is a two-step process: first, include the code necessary to dynamically load JavaScript, and then load the rest of the JavaScript code needed for page initialization. Since the first part of the code is as small as possible, potentially containing just the load Script() function, it downloads and executes quickly, and so shouldn’t cause much interference with the page. Once the initial code is in place, use it to load the remaining JavaScript. For example: 10 | Chapter 1: Loading and Execution
  • 36. <script type="text/javascript" src="loader.js"></script> <script type="text/javascript"> loadScript("the-rest.js", function(){ Application.init(); }); </script> Place this loading code just before the closing </body> tag. Doing so has several benefits. First, as discussed earlier, this ensures that JavaScript execution won’t prevent the rest of the page from being displayed. Second, when the second JavaScript file has finished downloading, all of the DOM necessary for the application has been created and is ready to be interacted with, avoiding the need to check for another event (such as window.onload) to know when the page is ready for initialization. Another option is to embed the loadScript() function directly into the page, thus avoiding another HTTP request. For example: <script type="text/javascript"> function loadScript(url, callback){ var script = document.createElement("script") script.type = "text/javascript"; if (script.readyState){ //IE script.onreadystatechange = function(){ if (script.readyState == "loaded" || script.readyState == "complete"){ script.onreadystatechange = null; callback(); } }; } else { //Others script.onload = function(){ callback(); }; } script.src = url; document.getElementsByTagName("head")[0].appendChild(script); } loadScript("the-rest.js", function(){ Application.init(); }); </script> If you decide to take the latter approach, it’s recommended to minify the initial script using a tool such as YUI Compressor (see Chapter 9) for the smallest byte-size impact on your page. Once the code for page initialization has been completely downloaded, you are free to continue using loadScript() to load additional functionality onto the page as needed. Nonblocking Scripts | 11
  • 37. The YUI 3 approach The concept of a small initial amount of code on the page followed by downloading additional functionality is at the core of the YUI 3 design. To use YUI 3 on your page, begin by including the YUI seed file: <script type="text/javascript" src="http://yui.yahooapis.com/combo?3.0.0/build/yui/yui-min.js"></script> The seed file is around 10 KB (6 KB gzipped) and includes enough functionality to download any other YUI components from the Yahoo! CDN. For example, if you’d like to use the DOM utility, you specify its name ("dom") with the YUI use() method and then provide a callback that will be executed when the code is ready: YUI().use("dom", function(Y){ Y.DOM.addClass(docment.body, "loaded"); }); This example creates a new instance of the YUI object and then calls the use() method. The seed file has all of the information about filenames and dependencies, so specifying "dom" actually builds up a combo-handler URL with all of the correct dependency files and creates a dynamic script element to download and execute those files. When all of the code is available, the callback method is called and the YUI instance is passed in as the argument, allowing you to immediately start using the newly downloaded functionality. The LazyLoad library For a more general-purpose tool, Ryan Grove of Yahoo! Search created the LazyLoad library (available at http://github.com/rgrove/lazyload/). LazyLoad is a more powerful version of the loadScript() function. When minified, the LazyLoad file is around 1.5 KB (minified, not gzipped). Example usage: <script type="text/javascript" src="lazyload-min.js"></script> <script type="text/javascript"> LazyLoad.js("the-rest.js", function(){ Application.init(); }); </script> LazyLoad is also capable of downloading multiple JavaScript files and ensuring that they are executed in the correct order in all browsers. To load multiple JavaScript files, just pass an array of URLs to the LazyLoad.js() method: <script type="text/javascript" src="lazyload-min.js"></script> <script type="text/javascript"> LazyLoad.js(["first-file.js", "the-rest.js"], function(){ Application.init(); }); </script> 12 | Chapter 1: Loading and Execution
  • 38. Even though the files are downloaded in a nonblocking fashion using dynamic script loading, it’s recommended to have as few files as possible. Each download is still a separate HTTP request, and the callback function won’t execute until all of the files have been downloaded and executed. LazyLoad is also capable of loading CSS files dynamically. This is typi- cally less of an issue because CSS file downloads are always done in parallel and don’t block other page activities. The LABjs library Another take on nonblocking JavaScript loading is LABjs (http://labjs.com/), an open source library written by Kyle Simpson with input from Steve Souders. This library provides more fine-grained control over the loading process and tries to download as much code in parallel as possible. LABjs is also quite small, 4.5 KB (minified, not gzipped), and so has a minimal page footprint. Example usage: <script type="text/javascript" src="lab.js"></script> <script type="text/javascript"> $LAB.script("the-rest.js") .wait(function(){ Application.init(); }); </script> The $LAB.script() method is used to define a JavaScript file to download, whereas $LAB.wait() is used to indicate that execution should wait until the file is downloaded and executed before running the given function. LABjs encourages chaining, so every method returns a reference to the $LAB object. To download multiple JavaScript files, just chain another $LAB.script() call: <script type="text/javascript" src="lab.js"></script> <script type="text/javascript"> $LAB.script("first-file.js") .script("the-rest.js") .wait(function(){ Application.init(); }); </script> What sets LABjs apart is its ability to manage dependencies. Normal inclusion with <script> tags means that each file is downloaded (either sequentially or in parallel, as mentioned previously) and then executed sequentially. In some cases this is truly nec- essary, but in others it is not. LABjs allows you to specify which files should wait for others by using wait(). In the previous example, the code in first-file.js is not guaranteed to execute before the code in the-rest.js. To guarantee this, you must add a wait() call after the first script(): Nonblocking Scripts | 13
  • 39. <script type="text/javascript" src="lab.js"></script> <script type="text/javascript"> $LAB.script("first-file.js").wait() .script("the-rest.js") .wait(function(){ Application.init(); }); </script> Now the code in first-file.js is guaranteed to execute before the code in the-rest.js, al- though the contents of the files are downloaded in parallel. Summary Managing JavaScript in the browser is tricky because code execution blocks other browser processes such as UI painting. Every time a <script> tag is encountered, the page must stop and wait for the code to download (if external) and execute before continuing to process the rest of the page. There are, however, several ways to minimize the performance impact of JavaScript: • Put all <script> tags at the bottom of the page, just inside of the closing </body> tag. This ensures that the page can be almost completely rendered before script execution begins. • Group scripts together. The fewer <script> tags on the page, the faster the page can be loaded and become interactive. This holds true both for <script> tags load- ing external JavaScript files and those with inline code. • There are several ways to download JavaScript in a nonblocking fashion: —Use the defer attribute of the <script> tag (Internet Explorer and Firefox 3.5+ only) —Dynamically create <script> elements to download and execute the code —Download the JavaScript code using an XHR object, and then inject the code into the page By using these strategies, you can greatly improve the perceived performance of a web application that requires a large amount of JavaScript code. 14 | Chapter 1: Loading and Execution
  • 40. CHAPTER 2 Data Access One of the classic computer science problems is determining where data should be stored for optimal reading and writing. Where data is stored is related to how quickly it can be retrieved during code execution. This problem in JavaScript is somewhat simplified because of the small number of options for data storage. Similar to other languages, though, where data is stored can greatly affect how quickly it can be accessed later. There are four basic places from which data can be accessed in JavaScript: Literal values Any value that represents just itself and isn’t stored in a particular location. Java- Script can represent strings, numbers, Booleans, objects, arrays, functions, regular expressions, and the special values null and undefined as literals. Variables Any developer-defined location for storing data created by using the var keyword. Array items A numerically indexed location within a JavaScript Array object. Object members A string-indexed location within a JavaScript object. Each of these data storage locations has a particular cost associated with reading and writing operations involving the data. In most cases, the performance difference be- tween accessing information from a literal value versus a local variable is trivial. Ac- cessing information from array items and object members is more expensive, though exactly which is more expensive depends heavily on the browser. Figure 2-1 shows the relative speed of accessing 200,000 values from each of these four locations in various browsers. Older browsers using more traditional JavaScript engines, such as Firefox 3, Internet Explorer, and Safari 3.2, show a much larger amount of time taken to access values versus browsers that use optimizing JavaScript engines. The general trends, however, remain the same across all browsers: literal value and local variable access tend to be faster than array item and object member access. The one exception, Firefox 3, 15
  • 41. optimized array item access to be much faster. Even so, the general advice is to use literal values and local variables whenever possible and limit use of array items and object members where speed of execution is a concern. To that end, there are several patterns to look for, avoid, and optimize in your code. Managing Scope The concept of scope is key to understanding JavaScript not just from a performance perspective, but also from a functional perspective. Scope has many effects in Java- Script, from determining what variables a function can access to assigning the value of this. There are also performance considerations when dealing with JavaScript scopes, but to understand how speed relates to scope, it’s necessary to understand exactly how scope works. Scope Chains and Identifier Resolution Every function in JavaScript is represented as an object—more specifically, as an in- stance of Function. Function objects have properties just like any other object, and these includeboththepropertiesthatyoucanaccessprogrammaticallyandaseriesofinternal properties that are used by the JavaScript engine but are not accessible through code. One of these properties is [[Scope]], as defined by ECMA-262, Third Edition. Figure 2-1. Time per 200,000 reads from various data locations 16 | Chapter 2: Data Access
  • 42. The internal [[Scope]] property contains a collection of objects representing the scope in which the function was created. This collection is called the function’s scope chain and it determines the data that a function can access. Each object in the function’s scope chain is called a variable object, and each of these contains entries for variables in the form of key-value pairs. When a function is created, its scope chain is populated with objects representing the data that is accessible in the scope in which the function was created. For example, consider the following global function: function add(num1, num2){ var sum = num1 + num2; return sum; } When the add() function is created, its scope chain is populated with a single variable object: the global object representing all of the variables that are globally defined. This global object contains entries for window, navigator, and document, to name a few. Figure 2-2 shows this relationship (note the global object in this figure shows only a few of the global variables as an example; there are many others). Figure 2-2. Scope chain for the add() function The add function’s scope chain is later used when the function is executed. Suppose that the following code is executed: var total = add(5, 10); Executing the add function triggers the creation of an internal object called an execution context. An execution context defines the environment in which a function is being executed. Each execution context is unique to one particular execution of the function, and so multiple calls to the same function result in multiple execution contexts being created. The execution context is destroyed once the function has been completely executed. Managing Scope | 17
  • 43. An execution context has its own scope chain that is used for identifier resolution. When the execution context is created, its scope chain is initialized with the objects contained in the executing function’s [[Scope]] property. These values are copied over into the execution context scope chain in the order in which they appear in the function. Once this is complete, a new object called the activation object is created for the exe- cution context. The activation object acts as the variable object for this execution and contains entries for all local variables, named arguments, the arguments collection, and this. This object is then pushed to the front of the scope chain. When the execution context is destroyed, so is the activation object. Figure 2-3 shows the execution context and its scope chain for the previous example code. Figure 2-3. Scope chain while executing add() Each time a variable is encountered during the function’s execution, the process of identifier resolution takes place to determine where to retrieve or store the data. During this process, the execution context’s scope chain is searched for an identifier with the samename.Thesearchbeginsatthefrontofthescopechain,intheexecutionfunction’s activation object. If found, the variable with the specified identifier is used; if not, the search continues on to the next object in the scope chain. This process continues until either the identifier is found or there are no more variable objects to search, in which case the identifier is deemed to be undefined. The same approach is taken for each identifier found during the function execution, so in the previous example, this would happen for sum, num1, and num2. It is this search process that affects performance. 18 | Chapter 2: Data Access
  • 44. Note that two variables with the same name may exist in different parts of the scope chain. In that case, the identifier is bound to the variable that is found first in the scope chain traversal, and the first variable is said to shadow the second. Identifier Resolution Performance Identifier resolution isn’t free, as in fact no computer operation really is without some sort of performance overhead. The deeper into the execution context’s scope chain an identifier exists, the slower it is to access for both reads and writes. Consequently, local variables are always the fastest to access inside of a function, whereas global variables will generally be the slowest (optimizing JavaScript engines are capable of tuning this in certain situations). Keep in mind that global variables always exist in the last variable object of the execution context’s scope chain, so they are always the furthest away to resolve. Figures 2-4 and 2-5 show the speed of identifier resolution based on their depth in the scope chain. A depth of 1 indicates a local variable. Figure 2-4. Identifier resolution for write operations Managing Scope | 19
  • 45. Figure 2-5. Identifier resolution for read operations The general trend across all browsers is that the deeper into the scope chain an identifier exists, the slower it will be read from or written to. Browsers with optimizing JavaScript engines, such as Chrome and Safari 4, don’t have this sort of performance penalty for accessing out-of-scope identifiers, whereas Internet Explorer, Safari 3.2, and others show a more drastic effect. It’s worth noting that earlier browsers, such as Internet Explorer 6 and Firefox 2, had incredibly steep slopes and would not even appear within the bounds of this graph at the high point if their data had been included. Given this information, it’s advisable to use local variables whenever possible to im- prove performance in browsers without optimizing JavaScript engines. A good rule of thumb is to always store out-of-scope values in local variables if they are used more than once within a function. Consider the following example: function initUI(){ var bd = document.body, links = document.getElementsByTagName("a"), i= 0, len = links.length; while(i < len){ update(links[i++]); } 20 | Chapter 2: Data Access
  • 46. document.getElementById("go-btn").onclick = function(){ start(); }; bd.className = "active"; } This function contains three references to document, which is a global object. The search for this variable must go all the way through the scope chain before finally being re- solved in the global variable object. You can mitigate the performance impact of re- peated global variable access by first storing the reference in a local variable and then using the local variable instead of the global. For example, the previous code can be rewritten as follows: function initUI(){ var doc = document, bd = doc.body, links = doc.getElementsByTagName("a"), i= 0, len = links.length; while(i < len){ update(links[i++]); } doc.getElementById("go-btn").onclick = function(){ start(); }; bd.className = "active"; } The updated version of initUI() first stores a reference to document in the local doc variable. Instead of accessing a global variables three times, that number is cut down to one. Accessing doc instead of document is faster because it’s a local variable. Of course, this simplistic function won’t show a huge performance improvement, because it’s not doing that much, but imagine larger functions with dozens of global variables being accessed repeatedly; that is where the more impressive performance improvements will be found. Scope Chain Augmentation Generally speaking, an execution context’s scope chain doesn’t change. There are, however, two statements that temporarily augment the execution context’s scope chain while it is being executed. The first of these is with. The with statement is used to create variables for all of an object’s properties. This mimics other languages with similar features and is usually seen as a convenience to avoid writing the same code repeatedly. The initUI() function can be written as the following: Managing Scope | 21
  • 47. function initUI(){ with (document){ //avoid! var bd = body, links = getElementsByTagName("a"), i= 0, len = links.length; while(i < len){ update(links[i++]); } getElementById("go-btn").onclick = function(){ start(); }; bd.className = "active"; } } This rewritten version of initUI() uses a with statement to avoid writing document else- where. Though this may seem more efficient, it actually creates a performance problem. When code execution flows into a with statement, the execution context’s scope chain is temporarily augmented. A new variable object is created containing all of the prop- erties of the specified object. That object is then pushed to the front of the scope chain, meaning that all of the function’s local variables are now in the second scope chain object and are therefore more expensive to access (see Figure 2-6). By passing the document object into the with statement, a new variable object containing all of the document object’s properties is pushed to the front of the scope chain. This makes it very fast to access document properties but slower to access the local variables such as bd. For this reason, it’s best to avoid using the with statement. As shown pre- viously, it’s just as easy to store document in a local variable and get the performance improvement that way. The with statement isn’t the only part of JavaScript that artificially augments the exe- cution context’s scope chain; the catch clause of the try-catch statement has the same effect. When an error occurs in the try block, execution automatically flows to the catch and the exception object is pushed into a variable object that is then placed at the front of the scope chain. Inside of the catch block, all variables local to the function are now in the second scope chain object. For example: try { methodThatMightCauseAnError(); } catch (ex){ alert(ex.message); //scope chain is augmented here } Note that as soon as the catch clause is finished executing, the scope chain returns to its previous state. 22 | Chapter 2: Data Access
  • 48. The try-catch statement is very useful when applied appropriately, and so it doesn’t make sense to suggest complete avoidance. If you do plan on using a try-catch, make sure that you understand the likelihood of error. A try-catch should never be used as the solution to a JavaScript error. If you know an error will occur frequently, then that indicates a problem with the code itself that should be fixed. You can minimize the performance impact of the catch clause by executing as little code as necessary within it. A good pattern is to have a method for handling errors that the catch clause can delegate to, as in this example: try { methodThatMightCauseAnError(); } catch (ex){ handleError(ex); //delegate to handler method } Here a handleError() method is the only code that is executed in the catch clause. This method is free to handle the error in an appropriate way and is passed the exception object generated from the error. Since there is just one statement executed and no local Figure 2-6. Augmented scope chain in a with statement Managing Scope | 23
  • 49. variables accessed, the temporary scope chain augmentation does not affect the per- formance of the code. Dynamic Scopes Both the with statement and the catch clause of a try-catch statement, as well as a function containing eval(), are all considered to be dynamic scopes. A dynamic scope is one that exists only through execution of code and therefore cannot be determined simply by static analysis (looking at the code structure). For example: function execute(code) { eval(code); function subroutine(){ return window; } var w = subroutine(); //what value is w? }; The execute() function represents a dynamic scope due to the use of eval(). The value of w can change based on the value of code. In most cases, w will be equal to the global window object, but consider the following: execute("var window = {};") In this case, eval() creates a local window variable in execute(), so w ends up equal to the local window instead of the global. There is no way to know if this is the case until the code is executed, which means the value of the window identifier cannot be predetermined. Optimizing JavaScript engines such as Safari’s Nitro try to speed up identifier resolution by analyzing the code to determine which variables should be accessible at any given time. These engines try to avoid the traditional scope chain lookup by indexing iden- tifiers for faster resolution. When a dynamic scope is involved, however, this optimi- zation is no longer valid. The engines need to switch back to a slower hash-based approach for identifier resolution that more closely mirrors traditional scope chain lookup. For this reason, it’s recommended to use dynamic scopes only when absolutely necessary. Closures, Scope, and Memory Closures are one of the most powerful aspects of JavaScript, allowing a function to access data that is outside of its local scope. The use of closures has been popularized through the writings of Douglas Crockford and is now ubiquitous in most complex 24 | Chapter 2: Data Access
  • 50. web applications. There is, however, a performance impact associated with using closures. To understand the performance issues with closures, consider the following: function assignEvents(){ var id = "xdi9592"; document.getElementById("save-btn").onclick = function(event){ saveDocument(id); }; } The assignEvents() function assigns an event handler to a single DOM element. This event handler is a closure, as it is created when the assignEvents() is executed and can access the id variable from the containing scope. In order for this closure to access id, a specific scope chain must be created. When assignEvents() is executed, an activation object is created that contains, among other things, the id variable. This becomes the first object in the execution context’s scope chain, with the global object coming second. When the closure is created, its [[Scope]] property is initialized with both of these objects (see Figure 2-7). Figure 2-7. Scope chains of the assignEvents() execution context and closure Since the closure’s [[Scope]] property contains references to the same objects as the execution context’s scope chain, there is a side effect. Typically, a function’s activation object is destroyed when the execution context is destroyed. When there’s a closure involved, though, the activation object isn’t destroyed, because a reference still exists Managing Scope | 25
  • 51. Another Random Scribd Document with Unrelated Content
  • 55. The Project Gutenberg eBook of Gunpowder and Ammunition, Their Origin and Progress
  • 56. This ebook is for the use of anyone anywhere in the United States and most other parts of the world at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this ebook or online at www.gutenberg.org. If you are not located in the United States, you will have to check the laws of the country where you are located before using this eBook. Title: Gunpowder and Ammunition, Their Origin and Progress Author: H. W. L. Hime Release date: March 22, 2017 [eBook #54411] Most recently updated: October 23, 2024 Language: English Credits: Produced by deaurider, Turgut Dincer and the Online Distributed Proofreading Team at http://www.pgdp.net (This book was produced from images made available by the HathiTrust Digital Library.) *** START OF THE PROJECT GUTENBERG EBOOK GUNPOWDER AND AMMUNITION, THEIR ORIGIN AND PROGRESS ***
  • 57. Cover image created by transcriber and placed in the public domain. GUNPOWDER AND AMMUNITION BY THE SAME AUTHOR STRAY MILITARY PAPERS. With 2 Plates. 8vo, 7s. 6d LUCIAN, THE SYRIAN SATIRIST. 8vo, 5s. net. THE OUTLINES OF QUATERNIONS. Crown 8vo, 10s. LONGMANS, GREEN, AND CO. LONDON, NEW YORK, AND BOMBAY GUNPOWDER AND AMMUNITION THEIR ORIGIN AND PROGRESS BY LIEUT.-COLONEL HENRY W. L. HIME (LATE) ROYAL ARTILLERY
  • 58. LONGMANS, GREEN, AND CO. 39 PATERNOSTER ROW, LONDON NEW YORK AND BOMBAY 1904 All rights reserved CONTENTS PART I THE ORIGIN OF GUNPOWDER CHAP. PAGE I. Introduction 3 II. Saltpetre 12 III. The Greeks 29 IV. Marcus Græcus 57 V. The Arabs 90 VI. The Hindus 105 VII. The Chinese 124 VIII. Friar Bacon 141 PART II THE PROGRESS OF AMMUNITION IX. Analytical Table of Ammunition 165 X. Hand Ammunition:— Fire-Arrows and Fire-Pikes 168 Hand Grenades 169 XI. War Rockets 172
  • 59. XII. Gunpowder 177 XIII. viShock Projectiles:— Darts, &c. 199 Round Shot 200 Case 207 Shrapnel 208 XIV. Igneous Projectiles:— Hot Shot 217 Incendiary Fireballs 217 Incendiary Shell 220 Carcasses 224 Explosive Fireballs 224 Explosive Shell 225 XV. Igniters:— Hot Wires, Priming Powder, Matches, and Portfires 228 Tubes 230 Time Fuzes 231 Percussion and Concussion Fuzes 244 XVI. Signals 246 TABLES TABLE PAGE I. Methods of Refining Saltpetre 27 II. Greek Fires 32 III. Sea Fires 41 IV. Analytical Table of Ammunition 167
  • 60. V. Price of English Powder at Various Times 184 VI. viiConnection between Size of Grain, Muzzle Velocity, and Pressure 195 VII. Composition of English Powder at Various Times 197 VIII. Composition of Foreign Powder at Various Times 198 IX. Price of Metals in 1375 and 1865 204 X. Comparative Cost of One Round fired with Shot of Different Materials, cir. 1375 205 XI. Comparative Pressure on Bore when firing Shot of Different Materials, cir. 1375 206 XII. Composition of Matches at Various Times 229 XIII. Composition of Time Fuzes at Various Times 243 XIV. Composition of Signal Rockets at Various Times 246 XV. Fixed Lights 246 XVI. Fireworks 247 Index 249 BOOKS OFTEN QUOTED The following works are frequently quoted, and are only designated by the author’s name. Thus, “Elliot,” ii. 75, means Sir H. M. Elliot’s “Hist. of India, as told, &c. &c.,” vol. ii. p. 75. Bacon, Roger, Opera quædam hactenus inedita, ed. by Professor Brewer; Rolls Series, 1859. Berthelot, M. P. E., La Chimie au Moyen Age, Paris, 1893.
  • 61. Brackenbury, Lieut.-General Sir H., G.C.B., “Ancient Cannon in Europe,” in vols. iv. and v. of Proceed. Roy. Artillery Institution, Woolwich, 1865-6. Elliot, Sir H. M., “Hist. of India, as told by its own Historians,” ed. by Professor J. Dowson, M.R.A.S., London, 1867-77. Jähns, Oberst-Lieut. M., Handbuch einer Geschichte des Kriegswesens, Leipsig, 1880. Napoleon III., Études sur le Passé et l’Avenir de l’Artillerie, Paris, 1846-71. Nye, Master-Gunner N., “Art of Gunnery,” to which is added a “Treatise on Artificial Fireworks” (separately paginated), London, 1647. Reinaud (Professor) et Favé (Capitaine), Du Feu Grégeois, &c., Paris, 1845. Romocki, S. J. von, Geschichte der Explosivstoffe, Hanover, 1895. Whitehorne, P., “Certain Waies for the ordering of Souldiers in Battelray,” London, 1560.
  • 62. PART I THE ORIGIN OF GUNPOWDER CHAPTER I INTRODUCTION I Much discussion has been caused in the past by the vagueness of the word gunpowder. The following are the meanings which this and a few other words bear in these pages:— Explosion.—The sudden and violent generation, with a loud noise and in a time inappreciable by the unaided senses, of a very great volume of gas, by the combustion of a body occupying a comparatively very small volume. Progressive Combustion.—Combustion which takes place in a time appreciable by the unaided senses, such as that of rocket composition or a bit of paper. Gunpowder.—A mixture of saltpetre, charcoal, and sulphur, which explodes. The signs of its explosion are a bright flash, a loud noise, and a large volume of smoke. Incendiary (for “incendiary composition”).—A substance or mixture which burns progressively, although fiercely, and is hard to put out.
  • 63. Machine always means an apparatus of the ballista type. Cannon includes bombards, mortars, guns, &c. Musket includes all hand firearms charged with gunpowder. II Of the many difficulties that beset the present inquiry, two deserve special mention. The first is the want of simple exactness in most early writers when recording the facts from which we have to draw our conclusions. At times their descriptions are so meagre that it is difficult, if not impossible, to decide whether certain projectiles were incendiary or explosive. At other times they abound in tropes and figures of speech which amount to an unintentional suggestio falsi. “The missiles spread themselves abroad like a cloud,” says a Spanish Arab; “they roar like thunder; they flame like a furnace; they reduce everything to ashes.”1 A projectile full of blazing Greek fire appeared to Joinville to be of portentous bulk. It flew through the midnight sky with thundering noise like a fiery dragon, followed by a long trail of flame; and it illumined the whole camp as with the light of day.2 Even to approach the truth, we must prune such figures of rhetoric; and this is a dangerous operation, for we may prune too much. The only safeguard against these suggestive metaphors is to keep steadily in view the distinctive peculiarities of incendiary and explosive projectiles. The incendiary shell was simply an envelope intended to convey into the interior of a fort, ship, &c., a quantity of combustible matter, which burned with such violence as to set fire to everything inflammable that was near it. The primary object of the explosive shell, on the other hand, was to blow up whatever it fell upon. It might occasionally, by the intense heat generated by the explosion,3 set fire to its surroundings when inflammable; but this was a mere incidental consequence of its action. Its aim and end was to explode.
  • 64. When a musket or cannon was fired there was a bright flash, a loud, momentary report, and a large volume of smoke.4 When an incendiary missile was discharged from a machine there was no flash, but little smoke, and the only sounds were the whizzing and sputtering of the burning mixture and the creaking and groaning of bolts, spars, ropes, &c.:— “With grisly soune out goth the greté gonne.”5 An explosive missile made its way through the air with little noise6 and less light:7 during its flight the blazing contents of the incendiary shell doubtless gave out much light and made a considerable noise, as described by many early writers. When an explosive shell reached its object there was, sooner or later (if it acted at all), an explosion, occasionally followed by a conflagration: an incendiary shell produced a conflagration only. The second difficulty arises from the change of meaning which many technical words have undergone in the lapse of years. The Arabic word barúd originally meant hail, was afterwards applied to saltpetre, and finally came to signify gunpowder. Our own word powder, which at first meant a fine, floury dust (pulvis), is often used in the present day to designate the stringy nitrocelluloid, cordite—smokeless powder. The Chinese word yo means gunpowder now, although its first meaning was a drug or plant. For centuries gunpowder was called kraut in Germany, and to this day it is called kruid in Holland. The Danish krud has not long become obsolete. The present Chinese word for firearm, huo p’áu, originally meant a machine for throwing blazing incendiary matter. The Arabic word bundúq at first meant a hazel-nut, secondly a clay-pellet the size of a hazel-nut, thirdly a bullet, and finally a firearm.8 The Latin nochus, a hazel-nut, is used, strange to say, to designate a smoke-ball by an old German military writer, Konrad Kyeser, whose “Bellifortis” dates from 1405.9 The word was also applied in Germany to bullets in general, and more particularly to projectiles discharged by machines.
  • 65. The word Artillery, both in France and England, originally meant bows and arrows. In his original account of the battle of Cressy, Froissart calls the apparatus and bolts of the Genoese crossbowmen leur artillerie; while a few lines further on he speaks of the kanons of the English.10 Ascham, writing in 1571, says: “Artillerie nowadays is taken for two things: gunnes and bowes.”11 Selden reminds us that gonne, our present gun, at first meant a machine of the ballista type.12 It is used in this sense in “Kyng Alisaunder,” 3268, written a.d. 1275-1300, and other metrical romances. Like the Arabic bundúq, the word is occasionally applied to the projectile, as in the “Avowing of Arthur,” st. 65. It is used in the modern sense, as cannon, in the “Vision of Piers the Plowman,” Passus xxi, C text, 293, a poem begun in 1362 and finally revised by its author in 1390; and in all three meanings by Chaucer, in poems written during the last quarter of the fourteenth century;—as a machine in the “Romaunt of the Rose,” 4176, as a projectile in the “Legende of Good Women,” 637, and as a cannon in the “Hous of Fame,” 533. “When the thing is perceived, the idea conceived,” says Professor Whitney, “(men) find in the existing resources of speech the means of its expression—a name which formerly belonged to something else in some way akin to it; a combination of words,” &c.13 For example, a word, W, which has always been the name of a thing, M, is applied to some new thing, N, which has been devised for the same use as M and answers the purpose better.14 W thus represents both M and N for an indefinite time,15 until M eventually drops into disuse and W comes to mean N and N only. The confusion necessarily arising from the equivocal meaning of W during this indefinite period, is entirely due, of course, to neglect of Horace’s advice to coin new names for new things.16 Had a new name been given to N from the first, no difficulty could possibly have ensued, and our way would have been straight and clear. But as matters have fallen out, not only have we to determine whether W means M or N, whenever it is used during the transition period,17 but we have to meet the arguments of those, never far off, who insist that
  • 66. because W meant N finally, it must have meant N at some bygone time when history and probability alike show that it meant M and M only. Examples, enough and to spare, of such arguments will be met with shortly. In consequence of the change of meaning which many military words have suffered, no translation of passages in foreign books containing ambiguous words should be relied upon, if access to the originals, or faithful copies of them, can be obtained. As an example of the necessity for this precaution, let us compare a few sentences relating to the siege of Jerusalem, a.d. 70, from the “Polychronicon” of Higden (d. cir. 1363), Rolls Series, iv. 429 ff., with the translations of them by Trevisa, 1385, and by the author of MS. Harl. No. 2261, of a.d. 1432-50. A (1) Inde Vespasianus ictu arietis murum conturbat (Higden). (2) Thanne Vaspacianus destourbed the wal with the stroke of an engyne (Trevisa). (3) Wherefore Vespasian troublede the walle soore with gunnes and other engynes (MS. Harl.). B (1) Josephus tamen ardenti oleo superjecto omnia machinamenta exussit (Higden). (2) But Joseph threwe out brennynge oyle uppon alle her gynnes and smoot all her gynnes (Trevisa). (3) Then Josephus destroyede alle theire instruments in castenge brennenge oyle on hit (MS. Harl.). C (1) Quo viso tanta vis telorum ex parte Titi proruit, ut unius de sociis Josephi occipitium lapide percussum ultra tertium stadium excuteretur (Higden).
  • 67. (2) Whan that was i-seie there fil so gret strenthe of castynge and of schot of Titus his side, that the noble knyght of oon of Josephus his felowes was i-smyte of that place with a stoon and flewe over the thrydde forlong (Trevisa). (3) Titus perceyvenge that, sende furthe a sawte and schotte gunnes to the walles in so much that the hynder parte of the hedde of a man stondenge by Josephus was smyten by the space of thre forlonges (MS. Harl.). D (1) Admotis tandem arietibus ad templum (Higden). (2) At the laste the engynes were remeved toward the temple (Trevisa). (3) Titus causede his gunners to schote at the Temple (MS. Harl.). No suspicion rests upon either of these translators; yet, were the original lost, a covert allusion to cannon might be discovered in Trevisa’s translation of B and C, and the Harleian translation of A, C, and D would be put forward as proof positive of their use. III The claims of the Greeks to the invention of gunpowder are examined in Chap. III. Chap. IV. is an inquiry into the nature and authorship of the Liber Ignium of Marcus Græcus. The claims of the Arabs, Hindus, Chinese, and English are considered in Chaps. V.-VIII. In Part II. the progress of Ammunition is very briefly traced from the introduction of cannon to the introduction of breechloading arms. As the book is addressed to the officers of the Army, who seldom have a library at command, the authorities for the statements of important facts are generally given at length. On all controversial points, when a foreign authority is quoted the original18 is given as well as the translation. I have endeavoured to acknowledge my obligation in all cases where quotations have been borrowed from others without verification.
  • 68. The invention of gunpowder was impossible until the properties of saltpetre had become known. We proceed, therefore, in the following chapter to determine the approximate date of the discovery of this salt. CHAPTER II SALTPETRE The attention of the ancients was naturally attracted by the efflorescences which form on certain stones, on walls, and in caves and cellars; and the Hindus and nomad Arabs must have noticed the deflagration of at least one of them when a fire was lit on it. These efflorescences consist of various salts,—sulphate and carbonate of soda, chloride of sodium, saltpetre, &c.—but they are so similar in appearance and taste, the only two criteria known in primitive times,19 that early observers succeeded in discriminating only one of them, common salt, from the rest. So close, in fact, is the resemblance between potash and soda, that their radical difference was only finally established by Du Hamel in 1736. Common salt received a distinctive name in remote times; all other salts were grouped together under such vague generic names as nitrum, natron, afro-nitron, &c. No trace of saltpetre has hitherto been found anywhere before the thirteenth century. The Greek alchemists of preceding centuries are silent. There is no saltpetre in the earliest recipe we possess for Greek fire, No. 26 of the Liber Ignium,20 ascribed to one Marcus Græcus, either as given in the Paris MSS. of 1300, or in the Munich MS. of 1438. It is true that the phrase sal coctus in this recipe has been translated by saltpetre in M. Hœfer’s untrustworthy Histoire de la Chimie, but as MM. Reinaud and Favé remark: “Rien n’autorise à
  • 69. traduire ainsi; le sel ordinaire a été souvent employé dans les artifices.”21 There is no instance in Latin, I believe, of saltpetre being designated otherwise than by sal petræ (or petrosus), or by nitrum, singly or in combination with some other word, as spuma nitri. The substitution of sal petræ for sal coctus, in later editions of the recipe, only shows that when the valuable properties of saltpetre became known it was employed instead of common salt. The very fact of the change having been made by most of the later alchemists, proves that to them sal coctus did not mean sal petræ, but something else. If sal coctus had meant sal petræ, what need was there for the change? This change, however, was not universal. In the version of recipe 26, given in the Livre de Canonnerie et Artifice de Feu, published in Paris in 1561, but written long before by a fire-worker well acquainted with saltpetre, we find: “prenez soufre vif, tarte, farcocoly (sarcocolla), peghel (pitch), sarcosti (sal coctum), &c.”22 The word coquo (to boil or evaporate) was necessarily connected with the preparation of common salt by evaporation,23 and coctus would correctly distinguish evaporated or artificial salt from natural or rock salt. In his “Natural History,” xxxi. 39 (7), Pliny tells us that salt is found round the edges of certain lakes in Sicily which are partially dried up in summer by the heat of the sun; while in Phrygia, where much greater evaporation takes place (ubi largius coquitur), a lake is dried up (and salt is deposited) to its very middle. Sal coctus was salt recovered from salt water by natural or artificial heat, as distinguished from natural, or rock salt, which was dug out of the ground.24 The Arab alchemists before the thirteenth century are as silent as the Greeks: nothing that can be identified with saltpetre is to be found in their voluminous works. The evidence of Geber, so often cited to prove that saltpetre was known to the Arabs in the ninth century, has been stripped of all authority by M. Berthelot, who has satisfactorily proved that there were two Gebers. The real Arab, Jabir, says nothing of saltpetre, but he mentions a salve used by naphtha-throwers25 as a safeguard against burns. The other Geber,
  • 70. or pseudo-Jabir, was acquainted with saltpetre, as well he might be; for he was a western who lived some time about the year 1300,26 and wrote a number of Latin works falsely purporting to be translations from the Arabic of the real Jabir. All doubt about the matter has been removed by M. Berthelot’s publication of the real Jabir’s Arabic writings.27 It has been also suspected that the sal Indicus of the Liber Sacerdotum, cir. tenth century,28 a salt again mentioned in the Liber Secretorum of Bubacar, cir. 1000,29 means saltpetre. Both these works are translations from the Arabic or Persian,30 and sal Indicus is the literal translation of the Persian— ‫هندي‬ ‫نمك‬ (nimaki Hindi) = ‫سياه‬ ‫نمك‬ (nimaki siyah) = salt of bitumen; a substance of the same family as the “salt of naphtha” also mentioned by Bubacar. There is no word for saltpetre in classical Sanskrit, sauverchala being a generic term for natural salts, which corresponded to, and was as comprehensive as the nitrum, spuma nitri, &c., of the West. “Recent Sanskrit formulæ for the preparation of mineral acids containing nitre, mention this salt under the name of soraka. This word, however, is not met with in any Sanskrit dictionary, and is evidently Sanskritised from the vernacular sora, a term of foreign origin.”31 Both Professor H. H. Wilson and Professor M. Williams, in their Sanskrit dictionaries, “erroneously render yavakshara as saltpetre, as also does Colebrooke in his ‘Amara-kosha.’”32 The word means impure carbonate of potash obtained by the incineration of barley straw.33 At length, however, notwithstanding coarse scales and clumsy apparatus, the want of all means of registering time and temperature, and the absence of any general principle to guide them in their researches, the alchemists succeeded in differentiating certain natural salts from the rest, and among them saltpetre. The Chinese were acquainted with it about the middle of the thirteenth century.34 Abd Allah ibn al-Baythar, who died at Damascus in 1248, tells us that the flower of the stone of Assos was called Chinese
  • 71. snow by the Egyptian physicians and barūd (i.e. saltpetre) by the (Arab) people of the West.35 Friar Bacon, whose De Secretis was written before 1249, and Hassan er-Rammah who wrote 1275-95, were thoroughly acquainted with the salt. A grand chemical discovery had been made, and saltpetre became known from China to Spain. The Egyptians thought fit to call saltpetre “Chinese snow,” but this does not justify the conclusion that the discovery was made by the Chinese. Consider our own phrases “Jerusalem” artichoke, “Welsh” onion, and “Turkey” cock. Jerusalem is a gardener’s corruption of girasole, the Turkey came from America, and the home of the Welsh onion is Siberia. The Persians called their native alkaline salt jamadi Chini, and no one will suggest that this substance came from China. It is evident from the way in which it is mentioned by the alchemists of the thirteenth century, and from their primitive methods of refining it, that saltpetre was then in its infancy. Roger Bacon speaks of it as one would speak of a substance recently discovered and still little known—“that salt which is called saltpetre” (illius salis qui sal petræ vocatur).36 Marcus Græcus thought it necessary to explain what the word means, in his 14th recipe which probably belongs to the latter years of the thirteenth century.37 The methods of refining the salt given by Marcus and Hassan leave no possible doubt that in their time it had but just come into use. It is true that Bacon’s method was much superior, if the solution of his steganogram given in Chap. viii. be accepted. But it would have been past all explanation had the method of the greatest natural philosopher of the age been found to be no better than that of an Arabic druggist or a European fireworker. As the matter is one of the greatest importance, the methods of all three are given in full, together with that of Whitehorne, 1560. The Waltham Abbey method is added, as a standard by which to judge them. To admit of easy comparison, the corresponding
  • 72. operations are marked with the same letter. The five methods are summed up in Table I. Waltham Abbey, 1860. A. Preparation of grough from natural saltpetre.38 Natural saltpetre is dissolved in boiling water, the insoluble impurities removed, and the solution evaporated by the sun or artificial heat. The solid residue is grough saltpetre, and contains 1 to 10 per cent. of impurities, consisting of the chlorides of potassium and sodium, sulphates of potash, soda, and calcium, vegetable matter, sand, and moisture. B. Boiling the solution of grough saltpetre. The grough saltpetre is placed in an open copper with a false bottom; water is added, and heat applied until the mixture boils at 110° C. C. Removal of the insoluble impurities. The scum which rises to the surface during this operation is removed by ladles; the sand and heavy impurities fall upon the false bottom, which is removed just before the mixture boils. The boiling is continued until the scum ceases to rise. D. Second boiling of the solution. Cold water is added; the solution is boiled for a few minutes, and then allowed to cool somewhat. E. Filtration. At 104.5° C. the mother liquid is transferred to a tank with holes in its bottom, closed by filters. F. Use of wood-ash, charcoal, &c. If the impurities prevent the liquid from passing freely through the filters, it is treated with glue, wood-ash, or, better, with a little
  • 73. animal charcoal, which seizes on the impurities and rises to the top as scum. G. Crystallisation. The mother liquid filters into the crystallising trough at 70.2° to 65.8° C. H. Stirring the depositing solution. The solution is kept in constant agitation by poles whilst cooling, in order that it may deposit in minute crystals, called saltpetre flour. Large crystals contain more or less of the impure mother liquid. I. Washing and drying. The agitation is discontinued at 25.8° C. and the mother liquid drawn off. The flour is drained on an inclined plane, transferred to a washing vat, where it is washed three times with cold water, and then finally dried. Whitehorne, 1560. A. Preparation of grough from natural saltpetre. On the bottom of a vessel pierced with “three or fower littell holes” is placed a linen cloth, “or else the end of a broom, or some straw.” A layer of nitrified earth, “a spanne thicknesse,” is laid on this, and on the earth “three fingers’ thicknesse” of a mixture of “two parts of unslacked lime and three of oke asshes, or other asshes.... And so, putting one rewe” of saltpetre alternately with one of the mixture, “you shall fill the tubbe ... within a spanne of (its mouth), and the rest you will fill with water.” The water, on percolating through the mass, drips into a brass cauldron which, when two-thirds full, is boiled “till it come to one-third part or thereabouts. And after take it off and put it to settell in a great vessell,” when it is to be “clarified and from earthe and grosse matter diligentlie purged.” B. Boiling the solution of grough saltpetre.
  • 74. Welcome to our website – the ideal destination for book lovers and knowledge seekers. With a mission to inspire endlessly, we offer a vast collection of books, ranging from classic literary works to specialized publications, self-development books, and children's literature. Each book is a new journey of discovery, expanding knowledge and enriching the soul of the reade Our website is not just a platform for buying books, but a bridge connecting readers to the timeless values of culture and wisdom. With an elegant, user-friendly interface and an intelligent search system, we are committed to providing a quick and convenient shopping experience. Additionally, our special promotions and home delivery services ensure that you save time and fully enjoy the joy of reading. Let us accompany you on the journey of exploring knowledge and personal growth! ebookultra.com