- Introduction
- Chapter 1 Values, Types, and Operators
- Chapter 2 Program Structure
- Expressions and statements
- Variables
- Keywords and reserved words
- The environment
- Functions
- The console.log function
- Return values
- prompt and confirm
- Control flow
- Conditional execution
- while and do loops
- Indenting Code
- for loops
- Breaking Out of a Loop
- Updating variables succinctly
- Dispatching on a value with switch
- Capitalization
- Comments
- Summary
- Exercises
- Chapter 3 Functions
- Chapter 4 Data Structures: Objects and Arrays
- Chapter 5 Higher-Order Functions
- Chapter 6 The Secret Life of Objects
- Chapter 7 Project: Electronic Life
- Chapter 8 Bugs and Error Handling
- Chapter 9 Regular Expressions
- Creating a regular expression
- Testing for matches
- Matching a set of characters
- Repeating parts of a pattern
- Grouping subexpressions
- Matches and groups
- The date type
- Word and string boundaries
- Choice patterns
- The mechanics of matching
- Backtracking
- The replace method
- Greed
- Dynamically creating RegExp objects
- The search method
- The lastIndex property
- Parsing an INI file
- International characters
- Summary
- Exercises
- Chapter 10 Modules
- Chapter 11 Project: A Programming Language
- Chapter 12 JavaScript and the Browser
- Chapter 13 The Document Object Model
- Chapter 14 Handling Events
- Chapter 15 Project: A Platform Game
- Chapter 16 Drawing on Canvas
- Chapter 17 HTTP
- Chapter 18 Forms and Form Fields
- Chapter 19 Project: A Paint Program
- Chapter 20 Node.js
- Chapter 21 Project: Skill-Sharing Website
- Eloquent JavaScript
- Exercise Hints
- Program Structure
- Functions
- Data Structures: Objects and Arrays
- Higher-Order Functions
- The Secret Life of Objects
- Project: Electronic Life
- Bugs and Error Handling
- Regular Expressions
- Modules
- Project: A Programming Language
- The Document Object Model
- Handling Events
- Project: A Platform Game
- Drawing on Canvas
- HTTP
- Forms and Form Fields
- Project: A Paint Program
- Node.js
- Project: Skill-Sharing Website
Slow-loading modules
Though it is possible to use the CommonJS module style when writing JavaScript for the browser, it is somewhat involved. The reason for this is that reading a file (module) from the Web is a lot slower than reading it from the hard disk. While a script is running in the browser, nothing else can happen to the website on which it runs, for reasons that will become clear in Chapter 14 . This means that if every require
call went and fetched something from some faraway web server, the page would freeze for a painfully long time while loading its scripts.
One way to work around this problem is to run a program like Browserify on your code before you serve it on a web page. This will look for calls to require
, resolve all dependencies, and gather the needed code into a single big file. The website itself can simply load this file to get all the modules it needs.
Another solution is to wrap the code that makes up your module in a function so that the module loader can first load its dependencies in the background and then call the function, initializing the module, when the dependencies have been loaded. That is what the Asynchronous Module Definition (AMD) module system does.
Our trivial program with dependencies would look like this in AMD:
define(["weekDay", "today"], function(weekDay, today) { console.log(weekDay.name(today.dayNumber())); });
The define
function is central to this approach. It takes first an array of module names and then a function that takes one argument for each dependency. It will load the dependencies (if they haven’t already been loaded) in the background, allowing the page to continue working while the files are being fetched. Once all dependencies are loaded, define
will call the function it was given, with the interfaces of those dependencies as arguments.
The modules that are loaded this way must themselves contain a call to define
. The value used as their interface is whatever was returned by the function passed to define
. Here is the weekDay
module again:
define([], function() { var names = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; return { name: function(number) { return names[number]; }, number: function(name) { return names.indexOf(name); } }; });
To be able to show a minimal implementation of define
, we will pretend we have a backgroundReadFile
function that takes a filename and a function and calls the function with the content of the file as soon as it has finished loading it. ( Chapter 17 will explain how to write that function.)
For the purpose of keeping track of modules while they are being loaded, the implementation of define
will use objects that describe the state of modules, telling us whether they are available yet and providing their interface when they are.
The getModule
function, when given a name, will return such an object and ensure that the module is scheduled to be loaded. It uses a cache object to avoid loading the same module twice.
var defineCache = Object.create(null); var currentMod = null; function getModule(name) { if (name in defineCache) return defineCache[name]; var module = {exports: null, loaded: false, onLoad: []}; defineCache[name] = module; backgroundReadFile(name, function(code) { currentMod = module; new Function("", code)(); }); return module; }
We assume the loaded file also contains a (single) call to define
. The currentMod
variable is used to tell this call about the module object that is currently being loaded so that it can update this object when it finishes loading. We will come back to this mechanism in a moment.
The define
function itself uses getModule
to fetch or create the module objects for the current module’s dependencies. Its task is to schedule the moduleFunction
(the function that contains the module’s actual code) to be run whenever those dependencies are loaded. For this purpose, it defines a function whenDepsLoaded
that is added to the onLoad
array of all dependencies that are not yet loaded. This function immediately returns if there are still unloaded dependencies, so it will do actual work only once, when the last dependency has finished loading. It is also called immediately, from define
itself, in case there are no dependencies that need to be loaded.
function define(depNames, moduleFunction) { var myMod = currentMod; var deps = depNames.map(getModule); deps.forEach(function(mod) { if (!mod.loaded) mod.onLoad.push(whenDepsLoaded); }); function whenDepsLoaded() { if (!deps.every(function(m) { return m.loaded; })) return; var args = deps.map(function(m) { return m.exports; }); var exports = moduleFunction.apply(null, args); if (myMod) { myMod.exports = exports; myMod.loaded = true; myMod.onLoad.forEach(function(f) { f(); }); } } whenDepsLoaded(); }
When all dependencies are available, whenDepsLoaded
calls the function that holds the module, giving it the dependencies’ interfaces as arguments.
The first thing define
does is store the value that currentMod
had when it was called in a variable myMod
. Remember that getModule
, just before evaluating the code for a module, stored the corresponding module object in currentMod
. This allows whenDepsLoaded
to store the return value of the module function in that module’s exports
property, set the module’s loaded
property to true, and call all the functions that are waiting for the module to load.
This code is a lot harder to follow than the require
function. Its execution does not follow a simple, predictable path. Instead, multiple operations are set up to happen at some unspecified time in the future, which obscures the way the code executes.
A real AMD implementation is, again, quite a lot more clever about resolving module names to actual URLs and generally more robust than the one shown previously. The RequireJS ( requirejs.org ) project provides a popular implementation of this style of module loader.
This is a book about getting computers to do what you want them to do. Computers are about as common as screwdrivers today, but they contain a lot more hidden complexity and thus are harder to operate and understand. To many, they remain alien, slightly threatening things.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论