The seajs module depends on loading and module execution, and the seajs module depends on loading.
This article describes how to load dependencies between seajs modules and how to execute modules. The following is a detailed introduction.
Entry Method
Each program has an entry method, similar to c'smain
Functions and seajs are no exception. Series 1 demo is used on the homepageseajs.use()
This is the entry method. The entry method can take two parameters. The first parameter is the module name, and the second parameter is the callback function. The entry method defines a new module, which depends on the module provided by the input parameter. Set the callback function of the new moduleloaded
Status. This callback function is mainly used to execute the factory functions of all dependent modules, and finally the callback provided in the execution entry method.
// Public API // The endpoint seajs. use = function (ids, callback) {Module. preload (function () {Module. use (ids, callback, data. cwd + "_ use _" + cid ()}) return seajs} // Load preload modules before all other modulesModule. preload = function (callback) {var preloadmod = data. preload var len = preloadmod. length if (len) {Module. use (preloadmod, function () {// Remove the loaded preload modules preloadmod. sp Lice (0, len) // Allow preload modules to add new preload modules Module. preload (callback)}, data. cwd + "_ preload _" + cid ()} else {callback ()} // Use function is equal to load a anonymous moduleModule. use = function (ids, callback, uri) {var mod = Module. get (uri, isArray (ids )? Ids: [ids]) mod. callback = function () {var exports = [] var uris = mod. resolve () for (var I = 0, len = uris. length; I <len; I ++) {exports [I] = cachedmods?uris= I =cmd.exe c ()} // the return value of the dependent module corresponding to the input parameter of the callback function if (callback) {callback. apply (global, exports)} delete mod. callback} mod. load ()}
Module.preload
It is used to pre-load plug-ins provided by seajs. It is not a major function and can be ignored. WhileModule.use
This is the core method. As mentioned earlier, this method creates a new module, sets the callback function, and loads all the dependent modules of the new module.
Load Method for dependency Loading
load
The method is the essence of seajs. This method mainly loads the dependent module and executes the callback function of the dependent module in sequence.seajs.use(“./name”)
Callback of the newly created module, that ismod.callback
.
load
Recursively load the dependency module. If the dependency module is dependent on other modules, load the module again. This is throughModule
Class_waitings
And_remain
.
Module. prototype. load = function () {var mod = this // If the module is being loaded, just wait onload call if (mod. status> = STATUS. LOADING) {return} mod. status = STATUS. LOADING // Emit 'load' event for plugins such as combo plugin var uris = mod. resolve () emit ("load", uris, mod) var len = mod. _ remain = uris. length var m // Initialize modules and register waitings for (var I = 0; I <len; I ++) {m = Module. get (uris [I]) // modify the dependency file's _ waiting attribute if (m. status <STATUS. LOADED) {// Maybe duplicate: When module has dupliate dependency, it shocould be it's count, not 1 m. _ waitings [mod. uri] = (m. _ waitings [mod. uri] | 0) + 1} else {mod. _ remain --} // load the dependency and execute the module if (mod. _ remain = 0) {mod. onload () return} // Begin parallel loading var requestCache ={} for (I = 0; I <len; I ++) {m = cachedmod [uris [I] // If the dependency is not loaded, fetch and seajs. the request function is bound to the corresponding requestCache. At this time, the module if (m. status <STATUS. FETCHING) {m. fetch (requestCache)} else if (m. status = STATUS. SAVED) {m. load ()} // Send all requests at last to avoid cache bug in IE6-9. issues #808 // load all modules for (var requestUri in requestCache) {if (requestCache. hasOwnProperty (requestUri) {// load the module requestCache [requestUri] ()} // After the dependency Module is loaded, run the callback function. // check whether other modules dependent on the Module can execute the Module. prototype. onload = function () {var mod = this mod. status = STATUS. LOADED if (mod. callback) {mod. callback ()} console. log (mod) // Notify waiting modules to fire onload var waitings = mod. _ waitings var uri, m for (uri in waitings) {if (waitings. hasOwnProperty (uri) {m = cachedmod [uri] m. _ remain-= waitings [uri] if (m. _ remain = 0) {m. onload () }}// Reduce memory taken delete mod. _ waitings delete mod. _ remain}
First, initialize_waitings
And_remain
Property, if_remain
If the value is 0, it means that no dependency or dependency has been loaded and can be executed.onload
Function. If the value is not 0fetch
Unloaded modules. Here is a small implementation technique, that is, loading all dependencies at the same time:requestCache
Object Storage and Loading Function: (INfetch
Defined in the function)
if (!emitData.requested) { requestCache ? requestCache[emitData.requestUri] = sendRequest : sendRequest() }
Where,sendRequest
The function is defined as follows:
function sendRequest() { seajs.request(emitData.requestUri, emitData.onRequest, emitData.charset) }
Load all dependencies in parallel. When the dependencies are loaded, executeonRequest
Callback, bubble up, load dependency until no dependency module is available.
Runonload
Function, in which the status is setloaded
, Executemod.callback,
Check and set_waitings
Attribute to determine whether there is any dependency on the lower-level module. If not, executemod.callback
, This tracing will eventually passseajs.use
The created anonymous Modulemod.callback
.
Example
A simple example is provided to illustrate the above process:
tst.html<script> seajs.use('./b');</script>-------------------------------------a.jsdefine(function(require,exports,module){ exports.add = function(a,b){ return a+b; }})------------------------------------b.jsdefine(function(require,exports,module){ var a = require("./a"); console.log(a.add(3,5));})
The debugging tool shows that the executiononload
Order:
Finally, we can see that the status code of the anonymous module is 4, that is, this module has not been executed. Indeed, it has not defined the factory function for the anonymous module and cannot be executed.
Exec for module execution
The module is executed inseajs.use
Defined inmod.callback
And call all dependentexec
Method to execute the program logic.exec
Methods include some important keywords or functions of commonJS, suchrequire
,exports
And so on. Let's take a look at the following:
Module.prototype.exe c = function () {var mod = this // When module is executed, do not execute it again. when module // is being executed, just return 'module. exports 'too, for avoiding // circularly calling if (mod. status> = STATUS. EXECUTING) {return mod. exports} mod. status = STATUS. EXECUTING // Create require var uri = mod. uri function require (id) {return module.get(require.resolve(id1_0000.exe c ( )} Require. resolve = function (id) {return Module. resolve (id, uri)} require. async = function (ids, callback) {Module. use (ids, callback, uri + "_ async _" + cid () return require} // Exec factory var factory = mod. factory // if the factory function has a return value, return; // if there is no return value, return mod. exports var exports = isFunction (factory )? Factory (require, mod. exports = {}, mod): factory if (exports = undefined) {exports = mod. exports} // Reduce memory leak delete mod. factory mod. exports = exports mod. status = STATUS. EXECUTED // Emit 'exec 'event emit ("exec", mod) return exports}
require
Function gets the module and executes the module's factory function to obtain the return value.require
Functionresolve
The method is to obtain the absolute url of the corresponding module name,require
Functionasync
The method asynchronously loads the dependency and executes the callback. For the return value of the factory method, if the factory method is an object, this isexports
Or if the factory method has a return value, it isexports
Value;or module.exports
Isexports
. When you can obtainexports
Value, set the statusexecuted
.
Note:If you wantexports
When assigning values to export an object
define(function(require,exports,module){ exports ={ add: function(a,b){ return a+b; } }})
It is unsuccessful. we can judge the final export by executing the above method.exports
First, the function does not return values. Second,Mod. exports is undefined
, The final exportedexports
Isundefined
. Why is this happening? This is because the value assignment is referenced in js. The assignment policy of js is "transfer by share", although the initialexports === module.exports
But whenexports
When an object is assignedexports
Point to this object,module.exports
But still not initialized,undefined
.
The correct statement is as follows:
define(function(require,exports,module){ module.exports ={ add: function(a,b){ return a+b; } }})
Summary
It can be said that the implementation of the core module of seajs has been explained, and many coding skills have been learned, the clever callback mode, and the careful consideration. Every part of the Code has taken into account the risk of Memory leakage and this pointer reference offset, and has been actively prevented. this spirit is worth learning.
For seajs, it took me less than a week to read the source code. from the beginning to the present, I really understood the importance of design ideas. Previously, I did not pay much attention to the implementation skills and thought that it could be implemented without bugs and robust. But now I realize that something is wrong, especially in the implementation of the load dependency module, skillful. The above is all the content of this article. I hope the content of this article will help you in your study or work. If you have any questions, please leave a message.