Seajs learning module dependency loading and module API export, seajsapi

Source: Internet
Author: User

Seajs learning module dependency loading and module API export, seajsapi

Preface

SeaJS is very powerful. SeaJS can load arbitrary JavaScript modules and css module styles. SeaJS will ensure that you have loaded other dependent modules into the script runtime environment when using a module.

By referring to the demo above, we combined the source code analysis to implement dependency loading and export of module APIs behind Simple API calls.

Module class and status class

First, a Module class is defined, which corresponds to a Module.

function Module(uri, deps) { this.uri = uri this.dependencies = deps || [] this.exports = null this.status = 0 // Who depends on me this._waitings = {} // The number of unloaded dependencies this._remain = 0}

Module has some attributes. The uri corresponds to the absolute url of the Module.Module.defineThe function will introduce dependencies. dependencies is the array of dependent modules; exports is the exported API; status is the current status code; _ waitings object is the hash table of other dependent modules of this module, the key is the url of other modules; _ remain is the counter, which records the number of modules that have not been loaded.

var STATUS = Module.STATUS = { // 1 - The `module.uri` is being fetched FETCHING: 1, // 2 - The meta data has been saved to cachedMods SAVED: 2, // 3 - The `module.dependencies` are being loaded LOADING: 3, // 4 - The module are ready to execute LOADED: 4, // 5 - The module is being executed EXECUTING: 5, // 6 - The `module.exports` is available EXECUTED: 6}

The above is a status object, recording the current status of the module: the initial status of the module is 0. When the module is loaded, the status is fetching; after the module is loaded and cached in cachemod, the status is saved; the loading status indicates that other dependent modules of this module are being loaded. loaded indicates that all dependent modules have been loaded and the callback function of this module is executed, set whether other modules dependent on this module have other dependent modules not loaded. If the loaded modules are completed, execute the callback function; executing status indicates that the module is being executed; executed indicates that the execution is completed, you can use the exports API.

Module Definition

CommonJS specificationsdefineFunction to define a module. Define can accept 1, 2, and 3 parameters, but for the Module/wrappings specification,module.declareOrdefineA function can only accept one parameter, that is, a factory function or an object. However, in principle, the number of parameters accepted is not essentially different, except that the library adds a module name to the background.

Seajs encouragementdefine(function(require,exports,module){})This Module definition method is a typical Module/wrappings standard implementation. However, after parsing the factory function in the backgroundrequireTo obtain the dependency module and set the id and url for the module.

// Define a moduleModule. define = function (id, deps, factory) {var argsLen = arguments. length // define (factory) if (argsLen = 1) {factory = id = undefined} else if (argsLen = 2) {factory = deps // define (deps, factory) if (isArray (id) {deps = id = undefined} // define (id, factory) else {deps = undefined }}// Parse dependencies according to the module factory code // If deps is not an array, The serialization factory function gets the input parameter. If (! IsArray (deps) & isFunction (factory) {deps = parseDependencies (factory. toString ()} var meta = {id: id, uri: Module. resolve (id), // absolute url deps: deps, factory: factory} // Try to derive uri in IE6-9 for anonymous modules // export the uri of the anonymous module if (! Meta. uri & doc. attachEvent) {var script = getCurrentScript () if (script) {meta. uri = script. src} // NOTE: If the id-deriving methods above is failed, then falls back // to use onload event to get the uri} // Emit 'define 'event, used in nocache plugin, seajs node version etc emit ("define", meta) meta. uri? Module. save (meta. uri, meta): // Save information for "saving" work in the script onload event anonymousMeta = meta}

At the end of the module definitionModule.saveMethod To save the module to the cache body of cachedmod.

parseDependenciesThe method is clever in obtaining the dependency module. It is represented by the function string and obtained using regular expressions.require(“…”)Module name.

Var REQUIRE_RE = /"(? : \ "| [^"]) * "| '(? : \ '| [^']) * '| \/\ * [\ S \ s] *? \ * \/| \/(? :\\\/| [^ \/\ R \ n]) + \/(? = [^ \/]) | \/. * | \. \ S * require | (? : ^ | [^ $]) \ Brequire \ s * \ (\ s * (["']) (. + ?) \ 1 \ s * \)/gvar SLASH_RE =/\\\\/gfunction parseDependencies (code) {var ret = [] // use function serialization (input factory) to search for require ("... ") keyword code. replace (SLASH_RE ,""). replace (REQUIRE_RE, function (m, m1, m2) {if (m2) {ret. push (m2) }}) return ret}

Asynchronous loading Module

The module can be loaded in multiple ways. xhr can be loaded synchronously or asynchronously, but it is difficult to use the same source. In additionscript tagIn IE and modern browsers, parallel loading and sequential execution can be ensured,script elementThis method can also ensure parallel loading but not sequential execution. Therefore, both methods can be used.

In seajsscript elementMethod To load js/css resources in parallel, and hack is made for loading css in the old webkit browser.

Function request (url, callback, charset) {var isCSS = IS_CSS_RE.test (url) var node = doc. createElement (isCSS? "Link": "script") if (charset) {var cs = isFunction (charset )? Charset (url): charset if (cs) {node. charset = cs }}// Add the onload function. AddOnload (node, callback, isCSS, url) if (isCSS) {node. rel = "stylesheet" node. href = url} else {node. async = true node. src = url} // For some cache cases in IE 6-8, the script executes IMMEDIATELY after // the end of the insert execution, so use 'currentlyaddingscript' to // hold current node, for deriving url in 'describe' call currentlyAddingScript = node // ref: #185 & http://dev.jquery.com/ Ticket/2709 baseElement? Head. insertBefore (node, baseElement): head. appendChild (node) currentlyAddingScript = null} function addOnload (node, callback, isCSS, url) {var supportOnload = "onload" in node // for Old WebKit and Old Firefox if (isCSS & (isOldWebKit |! SupportOnload) {setTimeout (function () {pollCss (node, callback)}, 1) // Begin after node insertion return} if (supportOnload) {node. onload = onload node. onerror = function () {emit ("error", {uri: url, node: node}) onload ()} else {node. onreadystatechange = function () {if (/loaded | complete /. test (node. readyState) {onload () }}function onload () {// Ensure only run once and handle memo Ry leak in IE node. onload = node. onerror = node. onreadystatechange = null // Remove the script to reduce memory leak if (! IsCSS &&! Data. debug) {head. removeChild (node)} // Dereference the node = null callback ()} // function pollCss (node, callback) {var sheet = node. sheet var isLoaded // for WebKit <536 if (isOldWebKit) {if (sheet) {isLoaded = true} // for Firefox <9.0 else if (sheet) {try {if (sheet.css Rules) {isLoaded = true} catch (ex) {// The value of 'ex. name 'is changed from "NS_ERROR_DOM_SECURITY_ERR" // to "SecurityError" since Firefox 13.0. but Firefox is less than 9.0 // in here, So it is OK to just rely on "NS_ERROR_DOM_SECURITY_ERR" if (ex. name = "NS_ERROR_DOM_SECURITY_ERR") {isLoaded = true }}settimeout (function () {if (isLoaded) {// Place callback here to give time for style rendering callback ()} else {pollCss (node, callback) }}, 20 )}

Pay attention to some details.script elementWhen inserting a script node, try to insert it into the head as the first child node. This is because of an undiscoverable bug:

GLOBALEVAL WORKS INCORRECTLY IN IE6 IF THE CURRENT PAGE HAS <BASE HREF> TAG IN THE HEAD

Fetch Module

When initializing the Module object, the status is 0. The js file corresponding to this object is not loaded. to load the js file, userequestMethod, but it is impossible to load the file only. You also need to set the status of the module object and other modules that the module depends on.

These logics arefetchMethods are embodied in:

// Fetch a module // load this module. The fetch function calls seajs. request function Module. prototype. fetch = function (requestCache) {var mod = this var uri = mod. uri mod. status = STATUS. FETCHING // Emit 'fetch' event for plugins such as combo plugin var emitData = {uri: uri} emit ("fetch", emitData) var requestUri = emitData. requestUri | uri // Empty uri or a non-CMD module if (! RequestUri | fetchedList [requestUri]) {mod. load () return} if (fetchingList [requestUri]) {callbackList [requestUri]. push (mod) return} fetchingList [requestUri] = true callbackList [requestUri] = [mod] // Emit 'request' event for plugins such as text plugin emit ("request ", emitData = {uri: uri, requestUri: requestUri, onRequest: onRequest, charset: data. charset}) if (! EmitData. requested) {requestCache? RequestCache [emitData. requestUri] = sendRequest: sendRequest ()} function sendRequest () {seajs. request (emitData. requestUri, emitData. onRequest, emitData. charset)} // callback function onRequest () {delete fetchingList [requestUri] fetchedList [requestUri] = true // Save meta data of anonymous module if (anonymousMeta) {Module. save (uri, anonymousMeta) anonymousMeta = null} // Call callbacks var m, MOD = callbackList [requestUri] delete callbackList [requestUri] while (m = Mod. shift () m. load ()}}

Whereseajs.requestIsrequestMethod.onRequestAs a callback function, it loads other dependent modules of this module.

Summary

The above is the dependency loading of the seajs module and the export of the module API. The editor will introduce the dependency loading between modules and the execution of modules in the next section. If you are interested, you can continue to follow the customer's home.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.