1 /*---------------------------------------start-------------------------------*/ 2 req({}); // num == 1 跳到 num == 2 3 4 //Exports some context-sensitive methods on global require. 5 each([ 6 ‘toUrl‘, 7 ‘undef‘, 8 ‘defined‘, 9 ‘specified‘ 10 ], function (prop) { 11 //Reference from contexts instead of early binding to default context, 12 //so that during builds, the latest instance of the default context 13 //with its config gets used. 14 req[prop] = function () { 15 var ctx = contexts[defContextName]; 16 return ctx.require[prop].apply(ctx, arguments); 17 }; 18 }); 19 20 if (isBrowser && !cfg.skipDataMain) {} //req.deps[mainscript] 21 22 23 //Set up with config info. 24 req(cfg); //最后启动。 按照之前写的num 一步一步的去加载。 25 26 /*----------------------------------------start---------------------------------*/ 27 //第一次 num == 2 28 //params 29 30 var deps = {}, 31 callback = undefined, 32 errback = undefined, 33 optional = undefined; 34 35 36 //--------------声明------------------ 37 var context = undefined, 38 config = undefined, 39 contextName = defContextName; 40 41 //-------------判断--------------- 42 43 config = {}; 44 deps = []; 45 46 //------------判断-------------- 47 context = contexts[contextName] = req.s.newContext(contextName); //跳到num ==3 48 49 //时间上就是执行 localRequire(deps, callback, errback); 50 context.require(deps, callback, errback); //跳到 num ==5 51 52 53 /*---------------------------------------end-------------------------------*/ 54 /* 55 * 56 * 57 * */ 58 /*---------------------------------------start-------------------------------*/ 59 //-----------------------进入核心函数-------------------------- 60 //第一次 61 //function newContext(contextName) num == 3 62 context = { 63 config: config, 64 contextName: contextName, 65 registry: registry, 66 defined: defined, 67 urlFetched: urlFetched, 68 defQueue: defQueue, 69 defQueueMap: {}, 70 Module: Module, 71 makeModuleMap: makeModuleMap, 72 nextTick: req.nextTick, 73 onError: onError, 74 75 /** 76 * Set a configuration for the context. 77 * @param {Object} cfg config object to integrate. 78 */ 79 configure: function (cfg) { 80 //Make sure the baseUrl ends in a slash. 81 if (cfg.baseUrl) { 82 if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== ‘/‘) { 83 cfg.baseUrl += ‘/‘; 84 } 85 } 86 87 // Convert old style urlArgs string to a function. 88 if (typeof cfg.urlArgs === ‘string‘) { 89 var urlArgs = cfg.urlArgs; 90 cfg.urlArgs = function(id, url) { 91 return (url.indexOf(‘?‘) === -1 ? ‘?‘ : ‘&‘) + urlArgs; 92 }; 93 } 94 95 //Save off the paths since they require special processing, 96 //they are additive. 97 var shim = config.shim, 98 objs = { 99 paths: true, 100 bundles: true, 101 config: true, 102 map: true 103 }; 104 105 eachProp(cfg, function (value, prop) { 106 if (objs[prop]) { 107 if (!config[prop]) { 108 config[prop] = {}; 109 } 110 mixin(config[prop], value, true, true); 111 } else { 112 config[prop] = value; 113 } 114 }); 115 116 //Reverse map the bundles 117 if (cfg.bundles) { 118 eachProp(cfg.bundles, function (value, prop) { 119 each(value, function (v) { 120 if (v !== prop) { 121 bundlesMap[v] = prop; 122 } 123 }); 124 }); 125 } 126 127 //Merge shim 128 if (cfg.shim) { 129 eachProp(cfg.shim, function (value, id) { 130 //Normalize the structure 131 if (isArray(value)) { 132 value = { 133 deps: value 134 }; 135 } 136 if ((value.exports || value.init) && !value.exportsFn) { 137 value.exportsFn = context.makeShimExports(value); 138 } 139 shim[id] = value; 140 }); 141 config.shim = shim; 142 } 143 144 //Adjust packages if necessary. 145 if (cfg.packages) { 146 each(cfg.packages, function (pkgObj) { 147 var location, name; 148 149 pkgObj = typeof pkgObj === ‘string‘ ? {name: pkgObj} : pkgObj; 150 151 name = pkgObj.name; 152 location = pkgObj.location; 153 if (location) { 154 config.paths[name] = pkgObj.location; 155 } 156 157 //Save pointer to main module ID for pkg name. 158 //Remove leading dot in main, so main paths are normalized, 159 //and remove any trailing .js, since different package 160 //envs have different conventions: some use a module name, 161 //some use a file name. 162 config.pkgs[name] = pkgObj.name + ‘/‘ + (pkgObj.main || ‘main‘) 163 .replace(currDirRegExp, ‘‘) 164 .replace(jsSuffixRegExp, ‘‘); 165 }); 166 } 167 168 //If there are any "waiting to execute" modules in the registry, 169 //update the maps for them, since their info, like URLs to load, 170 //may have changed. 171 eachProp(registry, function (mod, id) { 172 //If module already has init called, since it is too 173 //late to modify them, and ignore unnormalized ones 174 //since they are transient. 175 if (!mod.inited && !mod.map.unnormalized) { 176 mod.map = makeModuleMap(id, null, true); 177 } 178 }); 179 180 //If a deps array or a config callback is specified, then call 181 //require with those args. This is useful when require is defined as a 182 //config object before require.js is loaded. 183 if (cfg.deps || cfg.callback) { 184 context.require(cfg.deps || [], cfg.callback); 185 } 186 }, 187 188 makeShimExports: function (value) { 189 function fn() { 190 var ret; 191 if (value.init) { 192 ret = value.init.apply(global, arguments); 193 } 194 return ret || (value.exports && getGlobal(value.exports)); 195 } 196 return fn; 197 }, 198 199 makeRequire: function (relMap, options) { 200 options = options || {}; 201 202 function localRequire(deps, callback, errback) { 203 var id, map, requireMod; 204 205 if (options.enableBuildCallback && callback && isFunction(callback)) { 206 callback.__requireJsBuild = true; 207 } 208 209 if (typeof deps === ‘string‘) { 210 if (isFunction(callback)) { 211 //Invalid call 212 return onError(makeError(‘requireargs‘, ‘Invalid require call‘), errback); 213 } 214 215 //If require|exports|module are requested, get the 216 //value for them from the special handlers. Caveat: 217 //this only works while module is being defined. 218 if (relMap && hasProp(handlers, deps)) { 219 return handlers[deps](registry[relMap.id]); 220 } 221 222 //Synchronous access to one module. If require.get is 223 //available (as in the Node adapter), prefer that. 224 if (req.get) { 225 return req.get(context, deps, relMap, localRequire); 226 } 227 228 //Normalize module name, if it contains . or .. 229 map = makeModuleMap(deps, relMap, false, true); 230 id = map.id; 231 232 if (!hasProp(defined, id)) { 233 return onError(makeError(‘notloaded‘, ‘Module name "‘ + 234 id + 235 ‘" has not been loaded yet for context: ‘ + 236 contextName + 237 (relMap ? ‘‘ : ‘. Use require([])‘))); 238 } 239 return defined[id]; 240 } 241 242 //Grab defines waiting in the global queue. 243 intakeDefines(); 244 245 //Mark all the dependencies as needing to be loaded. 246 context.nextTick(function () { 247 //Some defines could have been added since the 248 //require call, collect them. 249 intakeDefines(); 250 251 requireMod = getModule(makeModuleMap(null, relMap)); 252 253 //Store if map config should be applied to this require 254 //call for dependencies. 255 requireMod.skipMap = options.skipMap; 256 257 requireMod.init(deps, callback, errback, { 258 enabled: true 259 }); 260 261 checkLoaded(); 262 }); 263 264 return localRequire; 265 } 266 267 mixin(localRequire, { 268 isBrowser: isBrowser, 269 270 /** 271 * Converts a module name + .extension into an URL path. 272 * *Requires* the use of a module name. It does not support using 273 * plain URLs like nameToUrl. 274 */ 275 toUrl: function (moduleNamePlusExt) { 276 var ext, 277 index = moduleNamePlusExt.lastIndexOf(‘.‘), 278 segment = moduleNamePlusExt.split(‘/‘)[0], 279 isRelative = segment === ‘.‘ || segment === ‘..‘; 280 281 //Have a file extension alias, and it is not the 282 //dots from a relative path. 283 if (index !== -1 && (!isRelative || index > 1)) { 284 ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); 285 moduleNamePlusExt = moduleNamePlusExt.substring(0, index); 286 } 287 288 return context.nameToUrl(normalize(moduleNamePlusExt, 289 relMap && relMap.id, true), ext, true); 290 }, 291 292 defined: function (id) { 293 return hasProp(defined, makeModuleMap(id, relMap, false, true).id); 294 }, 295 296 specified: function (id) { 297 id = makeModuleMap(id, relMap, false, true).id; 298 return hasProp(defined, id) || hasProp(registry, id); 299 } 300 }); 301 302 //Only allow undef on top level require calls 303 if (!relMap) { 304 localRequire.undef = function (id) { 305 //Bind any waiting define() calls to this context, 306 //fix for #408 307 takeGlobalQueue(); 308 309 var map = makeModuleMap(id, relMap, true), 310 mod = getOwn(registry, id); 311 312 mod.undefed = true; 313 removeScript(id); 314 315 delete defined[id]; 316 delete urlFetched[map.url]; 317 delete undefEvents[id]; 318 319 //Clean queued defines too. Go backwards 320 //in array so that the splices do not 321 //mess up the iteration. 322 eachReverse(defQueue, function(args, i) { 323 if (args[0] === id) { 324 defQueue.splice(i, 1); 325 } 326 }); 327 delete context.defQueueMap[id]; 328 329 if (mod) { 330 //Hold on to listeners in case the 331 //module will be attempted to be reloaded 332 //using a different config. 333 if (mod.events.defined) { 334 undefEvents[id] = mod.events; 335 } 336 337 cleanRegistry(id); 338 } 339 }; 340 } 341 342 return localRequire; 343 }, 344 345 /** 346 * Called to enable a module if it is still in the registry 347 * awaiting enablement. A second arg, parent, the parent module, 348 * is passed in for context, when this method is overridden by 349 * the optimizer. Not shown here to keep code compact. 350 */ 351 enable: function (depMap) { 352 var mod = getOwn(registry, depMap.id); 353 if (mod) { 354 getModule(depMap).enable(); 355 } 356 }, 357 358 /** 359 * Internal method used by environment adapters to complete a load event. 360 * A load event could be a script load or just a load pass from a synchronous 361 * load call. 362 * @param {String} moduleName the name of the module to potentially complete. 363 */ 364 completeLoad: function (moduleName) { 365 var found, args, mod, 366 shim = getOwn(config.shim, moduleName) || {}, 367 shExports = shim.exports; 368 369 takeGlobalQueue(); 370 371 while (defQueue.length) { 372 args = defQueue.shift(); 373 if (args[0] === null) { 374 args[0] = moduleName; 375 //If already found an anonymous module and bound it 376 //to this name, then this is some other anon module 377 //waiting for its completeLoad to fire. 378 if (found) { 379 break; 380 } 381 found = true; 382 } else if (args[0] === moduleName) { 383 //Found matching define call for this script! 384 found = true; 385 } 386 387 callGetModule(args); 388 } 389 context.defQueueMap = {}; 390 391 //Do this after the cycle of callGetModule in case the result 392 //of those calls/init calls changes the registry. 393 mod = getOwn(registry, moduleName); 394 395 if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) { 396 if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { 397 if (hasPathFallback(moduleName)) { 398 return; 399 } else { 400 return onError(makeError(‘nodefine‘, 401 ‘No define call for ‘ + moduleName, 402 null, 403 [moduleName])); 404 } 405 } else { 406 //A script that does not call define(), so just simulate 407 //the call for it. 408 callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); 409 } 410 } 411 412 checkLoaded(); 413 }, 414 415 /** 416 * Converts a module name to a file path. Supports cases where 417 * moduleName may actually be just an URL. 418 * Note that it **does not** call normalize on the moduleName, 419 * it is assumed to have already been normalized. This is an 420 * internal API, not a public one. Use toUrl for the public API. 421 */ 422 nameToUrl: function (moduleName, ext, skipExt) { 423 var paths, syms, i, parentModule, url, 424 parentPath, bundleId, 425 pkgMain = getOwn(config.pkgs, moduleName); 426 427 if (pkgMain) { 428 moduleName = pkgMain; 429 } 430 431 bundleId = getOwn(bundlesMap, moduleName); 432 433 if (bundleId) { 434 return context.nameToUrl(bundleId, ext, skipExt); 435 } 436 437 //If a colon is in the URL, it indicates a protocol is used and it is just 438 //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) 439 //or ends with .js, then assume the user meant to use an url and not a module id. 440 //The slash is important for protocol-less URLs as well as full paths. 441 if (req.jsExtRegExp.test(moduleName)) { 442 //Just a plain path, not module name lookup, so just return it. 443 //Add extension if it is included. This is a bit wonky, only non-.js things pass 444 //an extension, this method probably needs to be reworked. 445 url = moduleName + (ext || ‘‘); 446 } else { 447 //A module that needs to be converted to a path. 448 paths = config.paths; 449 450 syms = moduleName.split(‘/‘); 451 //For each module name segment, see if there is a path 452 //registered for it. Start with most specific name 453 //and work up from it. 454 for (i = syms.length; i > 0; i -= 1) { 455 parentModule = syms.slice(0, i).join(‘/‘); 456 457 parentPath = getOwn(paths, parentModule); 458 if (parentPath) { 459 //If an array, it means there are a few choices, 460 //Choose the one that is desired 461 if (isArray(parentPath)) { 462 parentPath = parentPath[0]; 463 } 464 syms.splice(0, i, parentPath); 465 break; 466 } 467 } 468 469 //Join the path parts together, then figure out if baseUrl is needed. 470 url = syms.join(‘/‘); 471 url += (ext || (/^data\:|^blob\:|\?/.test(url) || skipExt ? ‘‘ : ‘.js‘)); 472 url = (url.charAt(0) === ‘/‘ || url.match(/^[\w\+\.\-]+:/) ? ‘‘ : config.baseUrl) + url; 473 } 474 475 return config.urlArgs && !/^blob\:/.test(url) ? 476 url + config.urlArgs(moduleName, url) : url; 477 }, 478 479 //Delegates to req.load. Broken out as a separate function to 480 //allow overriding in the optimizer. 481 load: function (id, url) { 482 req.load(context, id, url); 483 }, 484 485 /** 486 * Executes a module callback function. Broken out as a separate function 487 * solely to allow the build system to sequence the files in the built 488 * layer in the right sequence. 489 * 490 * @private 491 */ 492 execCb: function (name, callback, args, exports) { 493 return callback.apply(exports, args); 494 }, 495 496 /** 497 * callback for script loads, used to check status of loading. 498 * 499 * @param {Event} evt the event from the browser for the script 500 * that was loaded. 501 */ 502 onScriptLoad: function (evt) { 503 //Using currentTarget instead of target for Firefox 2.0‘s sake. Not 504 //all old browsers will be supported, but this one was easy enough 505 //to support and still makes sense. 506 if (evt.type === ‘load‘ || 507 (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { 508 //Reset interactive script so a script node is not held onto for 509 //to long. 510 interactiveScript = null; 511 512 //Pull out the name of the module and the context. 513 var data = getScriptData(evt); 514 context.completeLoad(data.id); 515 } 516 }, 517 518 /** 519 * Callback for script errors. 520 */ 521 onScriptError: function (evt) { 522 var data = getScriptData(evt); 523 if (!hasPathFallback(data.id)) { 524 var parents = []; 525 eachProp(registry, function(value, key) { 526 if (key.indexOf(‘[email protected]‘) !== 0) { 527 each(value.depMaps, function(depMap) { 528 if (depMap.id === data.id) { 529 parents.push(key); 530 return true; 531 } 532 }); 533 } 534 }); 535 return onError(makeError(‘scripterror‘, ‘Script error for "‘ + data.id + 536 (parents.length ? 537 ‘", needed by: ‘ + parents.join(‘, ‘) : 538 ‘"‘), evt, [data.id])); 539 } 540 } 541 }; 542 543 //得到一个闭包环境 544 context.require = context.makeRequire(); //跳到num ===4 545 546 //return context; 547 /*---------------------------------------end-------------------------------*/ 548 /* 549 * 550 * 551 * 552 * 553 * 554 * */ 555 /*---------------------------------------start-------------------------------*/ 556 //--------------------------进入makeRequire------------------------ 557 //第一次 558 //params [relMap , options] num == 4 559 560 var relMap = undefined, 561 options = {}; 562 563 564 //声明localRequire函数 565 var localRequire= function(deps, callback, errback){}; 566 567 //给localRequire加属性 568 var fn1={ 569 isBrowser: isBrowser, 570 571 /** 572 * Converts a module name + .extension into an URL path. 573 * *Requires* the use of a module name. It does not support using 574 * plain URLs like nameToUrl. 575 */ 576 toUrl: function (moduleNamePlusExt) { 577 var ext, 578 index = moduleNamePlusExt.lastIndexOf(‘.‘), 579 segment = moduleNamePlusExt.split(‘/‘)[0], 580 isRelative = segment === ‘.‘ || segment === ‘..‘; 581 582 //Have a file extension alias, and it is not the 583 //dots from a relative path. 584 if (index !== -1 && (!isRelative || index > 1)) { 585 ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); 586 moduleNamePlusExt = moduleNamePlusExt.substring(0, index); 587 } 588 589 return context.nameToUrl(normalize(moduleNamePlusExt, 590 relMap && relMap.id, true), ext, true); 591 }, 592 593 defined: function (id) { 594 return hasProp(defined, makeModuleMap(id, relMap, false, true).id); 595 }, 596 597 specified: function (id) { 598 id = makeModuleMap(id, relMap, false, true).id; 599 return hasProp(defined, id) || hasProp(registry, id); 600 } 601 }; 602 603 604 //---------------------- 判断 if (!relMap)---------------------- 605 606 //加属性 607 608 var fn2 = undef = function(id){}; 609 610 //返回return localRequire; 611 612 //总结一下 就是返回一个函数,给他加了一些属性; 613 /*---------------------------------------end-------------------------------*/ 614 /* 615 * 616 * */ 617 618 /*---------------------------------------start-------------------------------*/ 619 // num == 5 620 intakeDefines() // 调到num == 6 621 /* 622 * while (defQueue.length) {}遍历 defQueue; 623 * 624 * 625 * 626 * */ 627 628 callGetModule(args); //args [id,deps,callb] 跳到num = 7 629 630 context.defQueueMap = {}; 631 632 context.nextTick(function () { 633 //Some defines could have been added since the 634 //require call, collect them. 635 intakeDefines(); 636 637 requireMod = getModule(makeModuleMap(null, relMap)); 638 639 //Store if map config should be applied to this require 640 //call for dependencies. 641 requireMod.skipMap = options.skipMap; 642 643 requireMod.init(deps, callback, errback, { 644 enabled: true 645 }); 646 647 checkLoaded(); 648 }); //跳转到 12 649 650 651 /*---------------------------------------end-------------------------------*/ 652 /* 653 * 654 * 655 * 656 * 657 * */ 658 /*---------------------------------------start-------------------------------*/ 659 /* function takeGlobalQueue() num == 6 660 * */ 661 662 //把globalDefQueue 里面通过define(id,desp,callback) 都放到 特定context 下的 defQueue 663 664 //并且最后清空 globalDefQueue = []; 665 666 /*---------------------------------------end-------------------------------*/ 667 /* 668 * 669 * 670 * 671 * 672 * */ 673 /*---------------------------------------start-------------------------------*/ 674 // function callGetModule(args) num == 7 675 676 //将 defined里没有的 id进行构建模块 677 if (!hasProp(defined, args[0])) { 678 getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); 679 } 680 681 makeModuleMap(args[0], null, true) //跳转到 num== 8 682 683 getModule(makeModuleMap(args[0], null, true)) //跳转到 num == 9 684 685 getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);//跳转到 num == 11 686 //生成的Module 里面的map属性 就是 makeModuleMap返回的对象。 687 688 689 /*---------------------------------------end-------------------------------*/ 690 /* 691 * 692 * 693 * 694 * 695 * */ 696 /*---------------------------------------start-------------------------------*/ 697 698 //function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) //num == 8 699 700 //返回obj 701 var obj = { 702 prefix: prefix, 703 name: normalizedName, 704 parentMap: parentModuleMap, 705 unnormalized: !!suffix, 706 url: url, 707 originalName: originalName, 708 isDefine: isDefine, 709 id: (prefix ? 710 prefix + ‘!‘ + normalizedName : 711 normalizedName) + suffix 712 }; 713 714 /*---------------------------------------end-------------------------------*/ 715 /* 716 * 717 * 718 * 719 * 720 * */ 721 /*-----------------------------------------start--------------------------------*/ 722 723 //function getModule(depMap) num == 9 724 var id = depMap.id, 725 mod = getOwn(registry, id); 726 727 if (!mod) { 728 mod = registry[id] = new context.Module(depMap); 729 } 730 731 new context.Module(depMap); //跳转到10 732 733 //return mod; 734 735 /*----------------------------------------end-------------------------*/ 736 /* 737 * 738 * 739 * 740 * 741 * */ 742 /*-----------------------------------------start--------------------------------*/ 743 //num ===10 744 Module = function (map) { 745 this.events = getOwn(undefEvents, map.id) || {}; 746 this.map = map; 747 this.shim = getOwn(config.shim, map.id); 748 this.depExports = []; 749 this.depMaps = []; 750 this.depMatched = []; 751 this.pluginMaps = {}; 752 this.depCount = 0; 753 754 /* this.exports this.factory 755 this.depMaps = [], 756 this.enabled, this.fetched 757 */ 758 }; 759 760 Module.prototype = { 761 init: function (depMaps, factory, errback, options) { 762 options = options || {}; 763 764 //Do not do more inits if already done. Can happen if there 765 //are multiple define calls for the same module. That is not 766 //a normal, common case, but it is also not unexpected. 767 if (this.inited) { 768 return; 769 } 770 771 this.factory = factory; 772 773 if (errback) { 774 //Register for errors on this module. 775 this.on(‘error‘, errback); 776 } else if (this.events.error) { 777 //If no errback already, but there are error listeners 778 //on this module, set up an errback to pass to the deps. 779 errback = bind(this, function (err) { 780 this.emit(‘error‘, err); 781 }); 782 } 783 784 //Do a copy of the dependency array, so that 785 //source inputs are not modified. For example 786 //"shim" deps are passed in here directly, and 787 //doing a direct modification of the depMaps array 788 //would affect that config. 789 this.depMaps = depMaps && depMaps.slice(0); 790 791 this.errback = errback; 792 793 //Indicate this module has be initialized 794 this.inited = true; 795 796 this.ignore = options.ignore; 797 798 //Could have option to init this module in enabled mode, 799 //or could have been previously marked as enabled. However, 800 //the dependencies are not known until init is called. So 801 //if enabled previously, now trigger dependencies as enabled. 802 if (options.enabled || this.enabled) { 803 //Enable this module and dependencies. 804 //Will call this.check() 805 this.enable(); 806 } else { 807 this.check(); 808 } 809 }, 810 811 defineDep: function (i, depExports) { 812 //Because of cycles, defined callback for a given 813 //export can be called more than once. 814 if (!this.depMatched[i]) { 815 this.depMatched[i] = true; 816 this.depCount -= 1; 817 this.depExports[i] = depExports; 818 } 819 }, 820 821 fetch: function () { 822 if (this.fetched) { 823 return; 824 } 825 this.fetched = true; 826 827 context.startTime = (new Date()).getTime(); 828 829 var map = this.map; 830 831 //If the manager is for a plugin managed resource, 832 //ask the plugin to load it now. 833 if (this.shim) { 834 context.makeRequire(this.map, { 835 enableBuildCallback: true 836 })(this.shim.deps || [], bind(this, function () { 837 return map.prefix ? this.callPlugin() : this.load(); 838 })); 839 } else { 840 //Regular dependency. 841 return map.prefix ? this.callPlugin() : this.load(); 842 } 843 }, 844 845 load: function () { 846 var url = this.map.url; 847 848 //Regular dependency. 849 if (!urlFetched[url]) { 850 urlFetched[url] = true; 851 context.load(this.map.id, url); 852 } 853 }, 854 855 /** 856 * Checks if the module is ready to define itself, and if so, 857 * define it. 858 */ 859 check: function () { 860 if (!this.enabled || this.enabling) { 861 return; 862 } 863 864 var err, cjsModule, 865 id = this.map.id, 866 depExports = this.depExports, 867 exports = this.exports, 868 factory = this.factory; 869 870 if (!this.inited) { 871 // Only fetch if not already in the defQueue. 872 if (!hasProp(context.defQueueMap, id)) { 873 this.fetch(); 874 } 875 } else if (this.error) { 876 this.emit(‘error‘, this.error); 877 } else if (!this.defining) { 878 //The factory could trigger another require call 879 //that would result in checking this module to 880 //define itself again. If already in the process 881 //of doing that, skip this work. 882 this.defining = true; 883 884 if (this.depCount < 1 && !this.defined) { 885 if (isFunction(factory)) { 886 //If there is an error listener, favor passing 887 //to that instead of throwing an error. However, 888 //only do it for define()‘d modules. require 889 //errbacks should not be called for failures in 890 //their callbacks (#699). However if a global 891 //onError is set, use that. 892 if ((this.events.error && this.map.isDefine) || 893 req.onError !== defaultOnError) { 894 try { 895 exports = context.execCb(id, factory, depExports, exports); 896 } catch (e) { 897 err = e; 898 } 899 } else { 900 exports = context.execCb(id, factory, depExports, exports); 901 } 902 903 // Favor return value over exports. If node/cjs in play, 904 // then will not have a return value anyway. Favor 905 // module.exports assignment over exports object. 906 if (this.map.isDefine && exports === undefined) { 907 cjsModule = this.module; 908 if (cjsModule) { 909 exports = cjsModule.exports; 910 } else if (this.usingExports) { 911 //exports already set the defined value. 912 exports = this.exports; 913 } 914 } 915 916 if (err) { 917 err.requireMap = this.map; 918 err.requireModules = this.map.isDefine ? [this.map.id] : null; 919 err.requireType = this.map.isDefine ? ‘define‘ : ‘require‘; 920 return onError((this.error = err)); 921 } 922 923 } else { 924 //Just a literal value 925 exports = factory; 926 } 927 928 this.exports = exports; 929 930 if (this.map.isDefine && !this.ignore) { 931 defined[id] = exports; 932 933 if (req.onResourceLoad) { 934 var resLoadMaps = []; 935 each(this.depMaps, function (depMap) { 936 resLoadMaps.push(depMap.normalizedMap || depMap); 937 }); 938 req.onResourceLoad(context, this.map, resLoadMaps); 939 } 940 } 941 942 //Clean up 943 cleanRegistry(id); 944 945 this.defined = true; 946 } 947 948 //Finished the define stage. Allow calling check again 949 //to allow define notifications below in the case of a 950 //cycle. 951 this.defining = false; 952 953 if (this.defined && !this.defineEmitted) { 954 this.defineEmitted = true; 955 this.emit(‘defined‘, this.exports); 956 this.defineEmitComplete = true; 957 } 958 959 } 960 }, 961 962 callPlugin: function () { 963 var map = this.map, 964 id = map.id, 965 //Map already normalized the prefix. 966 pluginMap = makeModuleMap(map.prefix); 967 968 //Mark this as a dependency for this plugin, so it 969 //can be traced for cycles. 970 this.depMaps.push(pluginMap); 971 972 on(pluginMap, ‘defined‘, bind(this, function (plugin) { 973 var load, normalizedMap, normalizedMod, 974 bundleId = getOwn(bundlesMap, this.map.id), 975 name = this.map.name, 976 parentName = this.map.parentMap ? this.map.parentMap.name : null, 977 localRequire = context.makeRequire(map.parentMap, { 978 enableBuildCallback: true 979 }); 980 981 //If current map is not normalized, wait for that 982 //normalized name to load instead of continuing. 983 if (this.map.unnormalized) { 984 //Normalize the ID if the plugin allows it. 985 if (plugin.normalize) { 986 name = plugin.normalize(name, function (name) { 987 return normalize(name, parentName, true); 988 }) || ‘‘; 989 } 990 991 //prefix and name should already be normalized, no need 992 //for applying map config again either. 993 normalizedMap = makeModuleMap(map.prefix + ‘!‘ + name, 994 this.map.parentMap); 995 on(normalizedMap, 996 ‘defined‘, bind(this, function (value) { 997 this.map.normalizedMap = normalizedMap; 998 this.init([], function () { return value; }, null, { 999 enabled: true, 1000 ignore: true 1001 }); 1002 })); 1003 1004 normalizedMod = getOwn(registry, normalizedMap.id); 1005 if (normalizedMod) { 1006 //Mark this as a dependency for this plugin, so it 1007 //can be traced for cycles. 1008 this.depMaps.push(normalizedMap); 1009 1010 if (this.events.error) { 1011 normalizedMod.on(‘error‘, bind(this, function (err) { 1012 this.emit(‘error‘, err); 1013 })); 1014 } 1015 normalizedMod.enable(); 1016 } 1017 1018 return; 1019 } 1020 1021 //If a paths config, then just load that file instead to 1022 //resolve the plugin, as it is built into that paths layer. 1023 if (bundleId) { 1024 this.map.url = context.nameToUrl(bundleId); 1025 this.load(); 1026 return; 1027 } 1028 1029 load = bind(this, function (value) { 1030 this.init([], function () { return value; }, null, { 1031 enabled: true 1032 }); 1033 }); 1034 1035 load.error = bind(this, function (err) { 1036 this.inited = true; 1037 this.error = err; 1038 err.requireModules = [id]; 1039 1040 //Remove temp unnormalized modules for this module, 1041 //since they will never be resolved otherwise now. 1042 eachProp(registry, function (mod) { 1043 if (mod.map.id.indexOf(id + ‘_unnormalized‘) === 0) { 1044 cleanRegistry(mod.map.id); 1045 } 1046 }); 1047 1048 onError(err); 1049 }); 1050 1051 //Allow plugins to load other code without having to know the 1052 //context or how to ‘complete‘ the load. 1053 load.fromText = bind(this, function (text, textAlt) { 1054 /*jslint evil: true */ 1055 var moduleName = map.name, 1056 moduleMap = makeModuleMap(moduleName), 1057 hasInteractive = useInteractive; 1058 1059 //As of 2.1.0, support just passing the text, to reinforce 1060 //fromText only being called once per resource. Still 1061 //support old style of passing moduleName but discard 1062 //that moduleName in favor of the internal ref. 1063 if (textAlt) { 1064 text = textAlt; 1065 } 1066 1067 //Turn off interactive script matching for IE for any define 1068 //calls in the text, then turn it back on at the end. 1069 if (hasInteractive) { 1070 useInteractive = false; 1071 } 1072 1073 //Prime the system by creating a module instance for 1074 //it. 1075 getModule(moduleMap); 1076 1077 //Transfer any config to this other module. 1078 if (hasProp(config.config, id)) { 1079 config.config[moduleName] = config.config[id]; 1080 } 1081 1082 try { 1083 req.exec(text); 1084 } catch (e) { 1085 return onError(makeError(‘fromtexteval‘, 1086 ‘fromText eval for ‘ + id + 1087 ‘ failed: ‘ + e, 1088 e, 1089 [id])); 1090 } 1091 1092 if (hasInteractive) { 1093 useInteractive = true; 1094 } 1095 1096 //Mark this as a dependency for the plugin 1097 //resource 1098 this.depMaps.push(moduleMap); 1099 1100 //Support anonymous modules. 1101 context.completeLoad(moduleName); 1102 1103 //Bind the value of that module to the value for this 1104 //resource ID. 1105 localRequire([moduleName], load); 1106 }); 1107 1108 //Use parentName here since the plugin‘s name is not reliable, 1109 //could be some weird string with no path that actually wants to 1110 //reference the parentName‘s path. 1111 plugin.load(map.name, localRequire, load, config); 1112 })); 1113 1114 context.enable(pluginMap, this); 1115 this.pluginMaps[pluginMap.id] = pluginMap; 1116 }, 1117 1118 enable: function () { 1119 enabledRegistry[this.map.id] = this; 1120 this.enabled = true; 1121 1122 //Set flag mentioning that the module is enabling, 1123 //so that immediate calls to the defined callbacks 1124 //for dependencies do not trigger inadvertent load 1125 //with the depCount still being zero. 1126 this.enabling = true; 1127 1128 //Enable each dependency 1129 each(this.depMaps, bind(this, function (depMap, i) { 1130 var id, mod, handler; 1131 1132 if (typeof depMap === ‘string‘) { 1133 //Dependency needs to be converted to a depMap 1134 //and wired up to this module. 1135 depMap = makeModuleMap(depMap, 1136 (this.map.isDefine ? this.map : this.map.parentMap), 1137 false, 1138 !this.skipMap); 1139 this.depMaps[i] = depMap; 1140 1141 handler = getOwn(handlers, depMap.id); 1142 1143 if (handler) { 1144 this.depExports[i] = handler(this); 1145 return; 1146 } 1147 1148 this.depCount += 1; 1149 1150 on(depMap, ‘defined‘, bind(this, function (depExports) { 1151 if (this.undefed) { 1152 return; 1153 } 1154 this.defineDep(i, depExports); 1155 this.check(); 1156 })); 1157 1158 if (this.errback) { 1159 on(depMap, ‘error‘, bind(this, this.errback)); 1160 } else if (this.events.error) { 1161 // No direct errback on this module, but something 1162 // else is listening for errors, so be sure to 1163 // propagate the error correctly. 1164 on(depMap, ‘error‘, bind(this, function(err) { 1165 this.emit(‘error‘, err); 1166 })); 1167 } 1168 } 1169 1170 id = depMap.id; 1171 mod = registry[id]; 1172 1173 //Skip special modules like ‘require‘, ‘exports‘, ‘module‘ 1174 //Also, don‘t call enable if it is already enabled, 1175 //important in circular dependency cases. 1176 if (!hasProp(handlers, id) && mod && !mod.enabled) { 1177 context.enable(depMap, this); 1178 } 1179 })); 1180 1181 //Enable each plugin that is used in 1182 //a dependency 1183 eachProp(this.pluginMaps, bind(this, function (pluginMap) { 1184 var mod = getOwn(registry, pluginMap.id); 1185 if (mod && !mod.enabled) { 1186 context.enable(pluginMap, this); 1187 } 1188 })); 1189 1190 this.enabling = false; 1191 1192 this.check(); 1193 }, 1194 1195 on: function (name, cb) { 1196 var cbs = this.events[name]; 1197 if (!cbs) { 1198 cbs = this.events[name] = []; 1199 } 1200 cbs.push(cb); 1201 }, 1202 1203 emit: function (name, evt) { 1204 each(this.events[name], function (cb) { 1205 cb(evt); 1206 }); 1207 if (name === ‘error‘) { 1208 //Now that the error handler was triggered, remove 1209 //the listeners, since this broken Module instance 1210 //can stay around for a while in the registry. 1211 delete this.events[name]; 1212 } 1213 } 1214 }; 1215 1216 /*-----------------------------------------end--------------------------------*/ 1217 /* 1218 * 1219 * 1220 * 1221 * */ 1222 /*-----------------------------------------start--------------------------------*/ 1223 //num = 11 1224 1225 //init: function (depMaps, factory, errback, options) {} 1226 1227 this.factory = factory; 1228 this.depMaps = depMaps && depMaps.slice(0); 1229 1230 this.errback = errback; 1231 1232 //Indicate this module has be initialized 1233 this.inited = true; 1234 1235 this.ignore = options.ignore; 1236 1237 //总结一句话 就是给module.绑定数据。 1238 /*----------------------------------------end-------------------------*/ 1239 /* 1240 * 1241 * */ 1242 /*----------------------------------------start-------------------------*/ 1243 num == 12 1244 1245 1246 /*----------------------------------------end-------------------------*/ 1247 /* 1248 * 1249 * */
/*---------------------------------------start-------------------------------*/req({}); // num == 1 跳到 num == 2 //Exports some context-sensitive methods on global require.each([ ‘toUrl‘, ‘undef‘, ‘defined‘, ‘specified‘], function (prop) { //Reference from contexts instead of early binding to default context, //so that during builds, the latest instance of the default context //with its config gets used.req[prop] = function () { var ctx = contexts[defContextName]; return ctx.require[prop].apply(ctx, arguments); };}); if (isBrowser && !cfg.skipDataMain) {} //req.deps[mainscript] //Set up with config info.req(cfg); //最后启动。 按照之前写的num 一步一步的去加载。 /*----------------------------------------start---------------------------------*///第一次 num == 2//params var deps = {}, callback = undefined, errback = undefined, optional = undefined; //--------------声明------------------var context = undefined, config = undefined, contextName = defContextName; //-------------判断--------------- config = {};deps = []; //------------判断--------------context = contexts[contextName] = req.s.newContext(contextName); //跳到num ==3 //时间上就是执行 localRequire(deps, callback, errback);context.require(deps, callback, errback); //跳到 num ==5 /*---------------------------------------end-------------------------------*//**** *//*---------------------------------------start-------------------------------*///-----------------------进入核心函数--------------------------//第一次//function newContext(contextName) num == 3context = { config: config, contextName: contextName, registry: registry, defined: defined, urlFetched: urlFetched, defQueue: defQueue, defQueueMap: {}, Module: Module, makeModuleMap: makeModuleMap, nextTick: req.nextTick, onError: onError, /** * Set a configuration for the context. * @param {Object} cfg config object to integrate. */configure: function (cfg) { //Make sure the baseUrl ends in a slash.if (cfg.baseUrl) { if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== ‘/‘) { cfg.baseUrl += ‘/‘; } } // Convert old style urlArgs string to a function.if (typeof cfg.urlArgs === ‘string‘) { var urlArgs = cfg.urlArgs; cfg.urlArgs = function(id, url) { return (url.indexOf(‘?‘) === -1 ? ‘?‘ : ‘&‘) + urlArgs; }; } //Save off the paths since they require special processing, //they are additive.var shim = config.shim, objs = { paths: true, bundles: true, config: true, map: true}; eachProp(cfg, function (value, prop) { if (objs[prop]) { if (!config[prop]) { config[prop] = {}; } mixin(config[prop], value, true, true); } else { config[prop] = value; } }); //Reverse map the bundlesif (cfg.bundles) { eachProp(cfg.bundles, function (value, prop) { each(value, function (v) { if (v !== prop) { bundlesMap[v] = prop; } }); }); } //Merge shimif (cfg.shim) { eachProp(cfg.shim, function (value, id) { //Normalize the structureif (isArray(value)) { value = { deps: value }; } if ((value.exports || value.init) && !value.exportsFn) { value.exportsFn = context.makeShimExports(value); } shim[id] = value; }); config.shim = shim; } //Adjust packages if necessary.if (cfg.packages) { each(cfg.packages, function (pkgObj) { var location, name; pkgObj = typeof pkgObj === ‘string‘ ? {name: pkgObj} : pkgObj; name = pkgObj.name; location = pkgObj.location; if (location) { config.paths[name] = pkgObj.location; } //Save pointer to main module ID for pkg name. //Remove leading dot in main, so main paths are normalized, //and remove any trailing .js, since different package //envs have different conventions: some use a module name, //some use a file name.config.pkgs[name] = pkgObj.name + ‘/‘ + (pkgObj.main || ‘main‘) .replace(currDirRegExp, ‘‘) .replace(jsSuffixRegExp, ‘‘); }); } //If there are any "waiting to execute" modules in the registry, //update the maps for them, since their info, like URLs to load, //may have changed.eachProp(registry, function (mod, id) { //If module already has init called, since it is too //late to modify them, and ignore unnormalized ones //since they are transient.if (!mod.inited && !mod.map.unnormalized) { mod.map = makeModuleMap(id, null, true); } }); //If a deps array or a config callback is specified, then call //require with those args. This is useful when require is defined as a //config object before require.js is loaded.if (cfg.deps || cfg.callback) { context.require(cfg.deps || [], cfg.callback); } }, makeShimExports: function (value) { function fn() { var ret; if (value.init) { ret = value.init.apply(global, arguments); } return ret || (value.exports && getGlobal(value.exports)); } return fn; }, makeRequire: function (relMap, options) { options = options || {}; function localRequire(deps, callback, errback) { var id, map, requireMod; if (options.enableBuildCallback && callback && isFunction(callback)) { callback.__requireJsBuild = true; } if (typeof deps === ‘string‘) { if (isFunction(callback)) { //Invalid callreturn onError(makeError(‘requireargs‘, ‘Invalid require call‘), errback); } //If require|exports|module are requested, get the //value for them from the special handlers. Caveat: //this only works while module is being defined.if (relMap && hasProp(handlers, deps)) { return handlers[deps](registry[relMap.id]); } //Synchronous access to one module. If require.get is //available (as in the Node adapter), prefer that.if (req.get) { return req.get(context, deps, relMap, localRequire); } //Normalize module name, if it contains . or ..map = makeModuleMap(deps, relMap, false, true); id = map.id; if (!hasProp(defined, id)) { return onError(makeError(‘notloaded‘, ‘Module name "‘ + id + ‘" has not been loaded yet for context: ‘ + contextName + (relMap ? ‘‘ : ‘. Use require([])‘))); } return defined[id]; } //Grab defines waiting in the global queue.intakeDefines(); //Mark all the dependencies as needing to be loaded.context.nextTick(function () { //Some defines could have been added since the //require call, collect them.intakeDefines(); requireMod = getModule(makeModuleMap(null, relMap)); //Store if map config should be applied to this require //call for dependencies.requireMod.skipMap = options.skipMap; requireMod.init(deps, callback, errback, { enabled: true}); checkLoaded(); }); return localRequire; } mixin(localRequire, { isBrowser: isBrowser, /** * Converts a module name + .extension into an URL path. * *Requires* the use of a module name. It does not support using * plain URLs like nameToUrl. */toUrl: function (moduleNamePlusExt) { var ext, index = moduleNamePlusExt.lastIndexOf(‘.‘), segment = moduleNamePlusExt.split(‘/‘)[0], isRelative = segment === ‘.‘ || segment === ‘..‘; //Have a file extension alias, and it is not the //dots from a relative path.if (index !== -1 && (!isRelative || index > 1)) { ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); moduleNamePlusExt = moduleNamePlusExt.substring(0, index); } return context.nameToUrl(normalize(moduleNamePlusExt, relMap && relMap.id, true), ext, true); }, defined: function (id) { return hasProp(defined, makeModuleMap(id, relMap, false, true).id); }, specified: function (id) { id = makeModuleMap(id, relMap, false, true).id; return hasProp(defined, id) || hasProp(registry, id); } }); //Only allow undef on top level require callsif (!relMap) { localRequire.undef = function (id) { //Bind any waiting define() calls to this context, //fix for #408takeGlobalQueue(); var map = makeModuleMap(id, relMap, true), mod = getOwn(registry, id); mod.undefed = true; removeScript(id); delete defined[id]; delete urlFetched[map.url]; delete undefEvents[id]; //Clean queued defines too. Go backwards //in array so that the splices do not //mess up the iteration.eachReverse(defQueue, function(args, i) { if (args[0] === id) { defQueue.splice(i, 1); } }); delete context.defQueueMap[id]; if (mod) { //Hold on to listeners in case the //module will be attempted to be reloaded //using a different config.if (mod.events.defined) { undefEvents[id] = mod.events; } cleanRegistry(id); } }; } return localRequire; }, /** * Called to enable a module if it is still in the registry * awaiting enablement. A second arg, parent, the parent module, * is passed in for context, when this method is overridden by * the optimizer. Not shown here to keep code compact. */enable: function (depMap) { var mod = getOwn(registry, depMap.id); if (mod) { getModule(depMap).enable(); } }, /** * Internal method used by environment adapters to complete a load event. * A load event could be a script load or just a load pass from a synchronous * load call. * @param {String} moduleName the name of the module to potentially complete. */completeLoad: function (moduleName) { var found, args, mod, shim = getOwn(config.shim, moduleName) || {}, shExports = shim.exports; takeGlobalQueue(); while (defQueue.length) { args = defQueue.shift(); if (args[0] === null) { args[0] = moduleName; //If already found an anonymous module and bound it //to this name, then this is some other anon module //waiting for its completeLoad to fire.if (found) { break; } found = true; } else if (args[0] === moduleName) { //Found matching define call for this script!found = true; } callGetModule(args); } context.defQueueMap = {}; //Do this after the cycle of callGetModule in case the result //of those calls/init calls changes the registry.mod = getOwn(registry, moduleName); if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) { if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { if (hasPathFallback(moduleName)) { return; } else { return onError(makeError(‘nodefine‘, ‘No define call for ‘ + moduleName, null, [moduleName])); } } else { //A script that does not call define(), so just simulate //the call for it.callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); } } checkLoaded(); }, /** * Converts a module name to a file path. Supports cases where * moduleName may actually be just an URL. * Note that it **does not** call normalize on the moduleName, * it is assumed to have already been normalized. This is an * internal API, not a public one. Use toUrl for the public API. */nameToUrl: function (moduleName, ext, skipExt) { var paths, syms, i, parentModule, url, parentPath, bundleId, pkgMain = getOwn(config.pkgs, moduleName); if (pkgMain) { moduleName = pkgMain; } bundleId = getOwn(bundlesMap, moduleName); if (bundleId) { return context.nameToUrl(bundleId, ext, skipExt); } //If a colon is in the URL, it indicates a protocol is used and it is just //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) //or ends with .js, then assume the user meant to use an url and not a module id. //The slash is important for protocol-less URLs as well as full paths.if (req.jsExtRegExp.test(moduleName)) { //Just a plain path, not module name lookup, so just return it. //Add extension if it is included. This is a bit wonky, only non-.js things pass //an extension, this method probably needs to be reworked.url = moduleName + (ext || ‘‘); } else { //A module that needs to be converted to a path.paths = config.paths; syms = moduleName.split(‘/‘); //For each module name segment, see if there is a path //registered for it. Start with most specific name //and work up from it.for (i = syms.length; i > 0; i -= 1) { parentModule = syms.slice(0, i).join(‘/‘); parentPath = getOwn(paths, parentModule); if (parentPath) { //If an array, it means there are a few choices, //Choose the one that is desiredif (isArray(parentPath)) { parentPath = parentPath[0]; } syms.splice(0, i, parentPath); break; } } //Join the path parts together, then figure out if baseUrl is needed.url = syms.join(‘/‘); url += (ext || (/^data\:|^blob\:|\?/.test(url) || skipExt ? ‘‘ : ‘.js‘)); url = (url.charAt(0) === ‘/‘ || url.match(/^[\w\+\.\-]+:/) ? ‘‘ : config.baseUrl) + url; } return config.urlArgs && !/^blob\:/.test(url) ? url + config.urlArgs(moduleName, url) : url; }, //Delegates to req.load. Broken out as a separate function to //allow overriding in the optimizer.load: function (id, url) { req.load(context, id, url); }, /** * Executes a module callback function. Broken out as a separate function * solely to allow the build system to sequence the files in the built * layer in the right sequence. * * @private*/execCb: function (name, callback, args, exports) { return callback.apply(exports, args); }, /** * callback for script loads, used to check status of loading. * * @param {Event} evt the event from the browser for the script * that was loaded. */onScriptLoad: function (evt) { //Using currentTarget instead of target for Firefox 2.0‘s sake. Not //all old browsers will be supported, but this one was easy enough //to support and still makes sense.if (evt.type === ‘load‘ || (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { //Reset interactive script so a script node is not held onto for //to long.interactiveScript = null; //Pull out the name of the module and the context.var data = getScriptData(evt); context.completeLoad(data.id); } }, /** * Callback for script errors. */onScriptError: function (evt) { var data = getScriptData(evt); if (!hasPathFallback(data.id)) { var parents = []; eachProp(registry, function(value, key) { if (key.indexOf(‘[email protected]‘) !== 0) { each(value.depMaps, function(depMap) { if (depMap.id === data.id) { parents.push(key); return true; } }); } }); return onError(makeError(‘scripterror‘, ‘Script error for "‘ + data.id + (parents.length ? ‘", needed by: ‘ + parents.join(‘, ‘) : ‘"‘), evt, [data.id])); } }}; //得到一个闭包环境context.require = context.makeRequire(); //跳到num ===4 //return context;/*---------------------------------------end-------------------------------*//******* *//*---------------------------------------start-------------------------------*///--------------------------进入makeRequire------------------------//第一次//params [relMap , options] num == 4 var relMap = undefined, options = {}; //声明localRequire函数var localRequire= function(deps, callback, errback){}; //给localRequire加属性var fn1={ isBrowser: isBrowser, /** * Converts a module name + .extension into an URL path. * *Requires* the use of a module name. It does not support using * plain URLs like nameToUrl. */toUrl: function (moduleNamePlusExt) { var ext, index = moduleNamePlusExt.lastIndexOf(‘.‘), segment = moduleNamePlusExt.split(‘/‘)[0], isRelative = segment === ‘.‘ || segment === ‘..‘; //Have a file extension alias, and it is not the //dots from a relative path.if (index !== -1 && (!isRelative || index > 1)) { ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); moduleNamePlusExt = moduleNamePlusExt.substring(0, index); } return context.nameToUrl(normalize(moduleNamePlusExt, relMap && relMap.id, true), ext, true);}, defined: function (id) { return hasProp(defined, makeModuleMap(id, relMap, false, true).id); }, specified: function (id) { id = makeModuleMap(id, relMap, false, true).id; return hasProp(defined, id) || hasProp(registry, id); }}; //---------------------- 判断 if (!relMap)---------------------- //加属性 var fn2 = undef = function(id){}; //返回return localRequire; //总结一下 就是返回一个函数,给他加了一些属性;/*---------------------------------------end-------------------------------*//*** */ /*---------------------------------------start-------------------------------*/// num == 5intakeDefines() // 调到num == 6/** while (defQueue.length) {}遍历 defQueue;**** */ callGetModule(args); //args [id,deps,callb] 跳到num = 7 context.defQueueMap = {}; context.nextTick(function () { //Some defines could have been added since the //require call, collect them.intakeDefines(); requireMod = getModule(makeModuleMap(null, relMap)); //Store if map config should be applied to this require //call for dependencies.requireMod.skipMap = options.skipMap; requireMod.init(deps, callback, errback, { enabled: true}); checkLoaded();}); //跳转到 12 /*---------------------------------------end-------------------------------*//****** *//*---------------------------------------start-------------------------------*//* function takeGlobalQueue() num == 6 * */ //把globalDefQueue 里面通过define(id,desp,callback) 都放到 特定context 下的 defQueue //并且最后清空 globalDefQueue = []; /*---------------------------------------end-------------------------------*//****** *//*---------------------------------------start-------------------------------*/// function callGetModule(args) num == 7 //将 defined里没有的 id进行构建模块if (!hasProp(defined, args[0])) { getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);} makeModuleMap(args[0], null, true) //跳转到 num== 8 getModule(makeModuleMap(args[0], null, true)) //跳转到 num == 9 getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);//跳转到 num == 11//生成的Module 里面的map属性 就是 makeModuleMap返回的对象。 /*---------------------------------------end-------------------------------*//****** *//*---------------------------------------start-------------------------------*/ //function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) //num == 8 //返回objvar obj = { prefix: prefix, name: normalizedName, parentMap: parentModuleMap, unnormalized: !!suffix, url: url, originalName: originalName, isDefine: isDefine, id: (prefix ? prefix + ‘!‘ + normalizedName : normalizedName) + suffix}; /*---------------------------------------end-------------------------------*//* * * * * * *//*-----------------------------------------start--------------------------------*/ //function getModule(depMap) num == 9var id = depMap.id, mod = getOwn(registry, id); if (!mod) { mod = registry[id] = new context.Module(depMap);} new context.Module(depMap); //跳转到10 //return mod; /*----------------------------------------end-------------------------*//* * * * * * *//*-----------------------------------------start--------------------------------*///num ===10Module = function (map) { this.events = getOwn(undefEvents, map.id) || {}; this.map = map; this.shim = getOwn(config.shim, map.id); this.depExports = []; this.depMaps = []; this.depMatched = []; this.pluginMaps = {}; this.depCount = 0; /* this.exports this.factory this.depMaps = [], this.enabled, this.fetched */}; Module.prototype = { init: function (depMaps, factory, errback, options) { options = options || {}; //Do not do more inits if already done. Can happen if there //are multiple define calls for the same module. That is not //a normal, common case, but it is also not unexpected.if (this.inited) { return; } this.factory = factory; if (errback) { //Register for errors on this module.this.on(‘error‘, errback); } else if (this.events.error) { //If no errback already, but there are error listeners //on this module, set up an errback to pass to the deps.errback = bind(this, function (err) { this.emit(‘error‘, err); }); } //Do a copy of the dependency array, so that //source inputs are not modified. For example //"shim" deps are passed in here directly, and //doing a direct modification of the depMaps array //would affect that config.this.depMaps = depMaps && depMaps.slice(0); this.errback = errback; //Indicate this module has be initializedthis.inited = true; this.ignore = options.ignore; //Could have option to init this module in enabled mode, //or could have been previously marked as enabled. However, //the dependencies are not known until init is called. So //if enabled previously, now trigger dependencies as enabled.if (options.enabled || this.enabled) { //Enable this module and dependencies. //Will call this.check()this.enable(); } else { this.check(); } }, defineDep: function (i, depExports) { //Because of cycles, defined callback for a given //export can be called more than once.if (!this.depMatched[i]) { this.depMatched[i] = true; this.depCount -= 1; this.depExports[i] = depExports; } }, fetch: function () { if (this.fetched) { return; } this.fetched = true; context.startTime = (new Date()).getTime(); var map = this.map; //If the manager is for a plugin managed resource, //ask the plugin to load it now.if (this.shim) { context.makeRequire(this.map, { enableBuildCallback: true})(this.shim.deps || [], bind(this, function () { return map.prefix ? this.callPlugin() : this.load(); })); } else { //Regular dependency.return map.prefix ? this.callPlugin() : this.load(); } }, load: function () { var url = this.map.url; //Regular dependency.if (!urlFetched[url]) { urlFetched[url] = true; context.load(this.map.id, url); } }, /** * Checks if the module is ready to define itself, and if so, * define it. */check: function () { if (!this.enabled || this.enabling) { return; } var err, cjsModule, id = this.map.id, depExports = this.depExports, exports = this.exports, factory = this.factory; if (!this.inited) { // Only fetch if not already in the defQueue.if (!hasProp(context.defQueueMap, id)) { this.fetch(); } } else if (this.error) { this.emit(‘error‘, this.error); } else if (!this.defining) { //The factory could trigger another require call //that would result in checking this module to //define itself again. If already in the process //of doing that, skip this work.this.defining = true; if (this.depCount < 1 && !this.defined) { if (isFunction(factory)) { //If there is an error listener, favor passing //to that instead of throwing an error. However, //only do it for define()‘d modules. require //errbacks should not be called for failures in //their callbacks (#699). However if a global //onError is set, use that.if ((this.events.error && this.map.isDefine) || req.onError !== defaultOnError) { try { exports = context.execCb(id, factory, depExports, exports); } catch (e) { err = e; } } else { exports = context.execCb(id, factory, depExports, exports); } // Favor return value over exports. If node/cjs in play, // then will not have a return value anyway. Favor // module.exports assignment over exports object.if (this.map.isDefine && exports === undefined) { cjsModule = this.module; if (cjsModule) { exports = cjsModule.exports; } else if (this.usingExports) { //exports already set the defined value.exports = this.exports; } } if (err) { err.requireMap = this.map; err.requireModules = this.map.isDefine ? [this.map.id] : null; err.requireType = this.map.isDefine ? ‘define‘ : ‘require‘; return onError((this.error = err)); } } else { //Just a literal valueexports = factory; } this.exports = exports; if (this.map.isDefine && !this.ignore) { defined[id] = exports; if (req.onResourceLoad) { var resLoadMaps = []; each(this.depMaps, function (depMap) { resLoadMaps.push(depMap.normalizedMap || depMap); }); req.onResourceLoad(context, this.map, resLoadMaps); } } //Clean upcleanRegistry(id); this.defined = true; } //Finished the define stage. Allow calling check again //to allow define notifications below in the case of a //cycle.this.defining = false; if (this.defined && !this.defineEmitted) { this.defineEmitted = true; this.emit(‘defined‘, this.exports); this.defineEmitComplete = true; } } }, callPlugin: function () { var map = this.map, id = map.id, //Map already normalized the prefix.pluginMap = makeModuleMap(map.prefix); //Mark this as a dependency for this plugin, so it //can be traced for cycles.this.depMaps.push(pluginMap); on(pluginMap, ‘defined‘, bind(this, function (plugin) { var load, normalizedMap, normalizedMod, bundleId = getOwn(bundlesMap, this.map.id), name = this.map.name, parentName = this.map.parentMap ? this.map.parentMap.name : null, localRequire = context.makeRequire(map.parentMap, { enableBuildCallback: true}); //If current map is not normalized, wait for that //normalized name to load instead of continuing.if (this.map.unnormalized) { //Normalize the ID if the plugin allows it.if (plugin.normalize) { name = plugin.normalize(name, function (name) { return normalize(name, parentName, true); }) || ‘‘; } //prefix and name should already be normalized, no need //for applying map config again either.normalizedMap = makeModuleMap(map.prefix + ‘!‘ + name, this.map.parentMap); on(normalizedMap, ‘defined‘, bind(this, function (value) { this.map.normalizedMap = normalizedMap; this.init([], function () { return value; }, null, { enabled: true, ignore: true}); })); normalizedMod = getOwn(registry, normalizedMap.id); if (normalizedMod) { //Mark this as a dependency for this plugin, so it //can be traced for cycles.this.depMaps.push(normalizedMap); if (this.events.error) { normalizedMod.on(‘error‘, bind(this, function (err) { this.emit(‘error‘, err); })); } normalizedMod.enable(); } return; } //If a paths config, then just load that file instead to //resolve the plugin, as it is built into that paths layer.if (bundleId) { this.map.url = context.nameToUrl(bundleId); this.load(); return; } load = bind(this, function (value) { this.init([], function () { return value; }, null, { enabled: true}); }); load.error = bind(this, function (err) { this.inited = true; this.error = err; err.requireModules = [id]; //Remove temp unnormalized modules for this module, //since they will never be resolved otherwise now.eachProp(registry, function (mod) { if (mod.map.id.indexOf(id + ‘_unnormalized‘) === 0) { cleanRegistry(mod.map.id); } }); onError(err); }); //Allow plugins to load other code without having to know the //context or how to ‘complete‘ the load.load.fromText = bind(this, function (text, textAlt) { /*jslint evil: true */var moduleName = map.name, moduleMap = makeModuleMap(moduleName), hasInteractive = useInteractive; //As of 2.1.0, support just passing the text, to reinforce //fromText only being called once per resource. Still //support old style of passing moduleName but discard //that moduleName in favor of the internal ref.if (textAlt) { text = textAlt; } //Turn off interactive script matching for IE for any define //calls in the text, then turn it back on at the end.if (hasInteractive) { useInteractive = false; } //Prime the system by creating a module instance for //it.getModule(moduleMap); //Transfer any config to this other module.if (hasProp(config.config, id)) { config.config[moduleName] = config.config[id]; } try { req.exec(text); } catch (e) { return onError(makeError(‘fromtexteval‘, ‘fromText eval for ‘ + id + ‘ failed: ‘ + e, e, [id])); } if (hasInteractive) { useInteractive = true; } //Mark this as a dependency for the plugin //resourcethis.depMaps.push(moduleMap); //Support anonymous modules.context.completeLoad(moduleName); //Bind the value of that module to the value for this //resource ID.localRequire([moduleName], load); }); //Use parentName here since the plugin‘s name is not reliable, //could be some weird string with no path that actually wants to //reference the parentName‘s path.plugin.load(map.name, localRequire, load, config); })); context.enable(pluginMap, this); this.pluginMaps[pluginMap.id] = pluginMap; }, enable: function () { enabledRegistry[this.map.id] = this; this.enabled = true; //Set flag mentioning that the module is enabling, //so that immediate calls to the defined callbacks //for dependencies do not trigger inadvertent load //with the depCount still being zero.this.enabling = true; //Enable each dependencyeach(this.depMaps, bind(this, function (depMap, i) { var id, mod, handler; if (typeof depMap === ‘string‘) { //Dependency needs to be converted to a depMap //and wired up to this module.depMap = makeModuleMap(depMap, (this.map.isDefine ? this.map : this.map.parentMap), false, !this.skipMap); this.depMaps[i] = depMap; handler = getOwn(handlers, depMap.id); if (handler) { this.depExports[i] = handler(this); return; } this.depCount += 1; on(depMap, ‘defined‘, bind(this, function (depExports) { if (this.undefed) { return; } this.defineDep(i, depExports); this.check(); })); if (this.errback) { on(depMap, ‘error‘, bind(this, this.errback)); } else if (this.events.error) { // No direct errback on this module, but something // else is listening for errors, so be sure to // propagate the error correctly.on(depMap, ‘error‘, bind(this, function(err) { this.emit(‘error‘, err); })); } } id = depMap.id; mod = registry[id]; //Skip special modules like ‘require‘, ‘exports‘, ‘module‘ //Also, don‘t call enable if it is already enabled, //important in circular dependency cases.if (!hasProp(handlers, id) && mod && !mod.enabled) { context.enable(depMap, this); } })); //Enable each plugin that is used in //a dependencyeachProp(this.pluginMaps, bind(this, function (pluginMap) { var mod = getOwn(registry, pluginMap.id); if (mod && !mod.enabled) { context.enable(pluginMap, this); } })); this.enabling = false; this.check(); }, on: function (name, cb) { var cbs = this.events[name]; if (!cbs) { cbs = this.events[name] = []; } cbs.push(cb); }, emit: function (name, evt) { each(this.events[name], function (cb) { cb(evt); }); if (name === ‘error‘) { //Now that the error handler was triggered, remove //the listeners, since this broken Module instance //can stay around for a while in the registry.delete this.events[name]; } }}; /*-----------------------------------------end--------------------------------*//***** *//*-----------------------------------------start--------------------------------*///num = 11 //init: function (depMaps, factory, errback, options) {} this.factory = factory;this.depMaps = depMaps && depMaps.slice(0); this.errback = errback; //Indicate this module has be initializedthis.inited = true; this.ignore = options.ignore; //总结一句话 就是给module.绑定数据。/*----------------------------------------end-------------------------*//* * * *//*----------------------------------------start-------------------------*/num == 12 /*----------------------------------------end-------------------------*//* * * */
时间: 2024-10-16 18:38:10