node.js require 实现机制初窥;pomelo代码分析5----------- pomel-loader模块

这篇主要介绍node.js的模块加载机制和代码分析。顺带提一下pomelo-loader。


下面我们来介绍pomelo的loader模块,

npmjs.org上面介绍如下:

pomelo中使用Convention over Configuration的形式管理工程目录,不同的功能按约定放在不同的目录下。pomelo-loader为pomelo提供了按目录加载模块的功能。

http://www.4shared.com/mp3/QDS1scPJce/20140123.html
http://www.4shared.com/mp3/t6ROiYfHce/20140123.html
http://www.4shared.com/mp3/cpcsTlq6ce/20140123.html
http://www.4shared.com/mp3/iaTqzYFLba/20140123.html
http://www.4shared.com/mp3/-14swvGuce/20140123.html
http://www.4shared.com/mp3/WFqmpV-Yba/20140123.html
http://www.4shared.com/mp3/_QVEctJVce/20140123.html
http://www.4shared.com/mp3/GPdKbOu_ba/20140123.html
http://www.4shared.com/mp3/TTweYSSlce/20140123.html
http://www.4shared.com/mp3/zgRH3b0Cba/20140123.html
http://www.4shared.com/mp3/33rxJFX3ce/20140123.html
http://www.4shared.com/mp3/LIESTUwQba/20140123.html
http://www.4shared.com/mp3/CZhfa5mpba/20140123.html
http://www.4shared.com/mp3/QT1sFuWgba/20140123.html
http://www.4shared.com/mp3/s1M6XqAlba/20140123.html
http://www.4shared.com/mp3/ZorUwpN0ba/20140123.html
http://www.4shared.com/mp3/YkSqfYFGce/20140123.html
http://www.4shared.com/mp3/uYtS-VM-ba/20140123.html
http://www.4shared.com/mp3/NJewkiHbba/20140123.html
http://www.4shared.com/mp3/stnZvAyKba/20140123.html
http://www.4shared.com/mp3/AH26PuAjba/20140123.html
http://www.4shared.com/mp3/BgMKHWuhba/20140123.html
http://www.4shared.com/mp3/1CDYxo4Kce/20140123.html
http://www.4shared.com/mp3/C3GlnJEYce/20140123.html
http://www.4shared.com/mp3/13y_mDlsba/20140123.html
http://www.4shared.com/mp3/7Xxl7C-nce/20140123.html
http://www.4shared.com/mp3/yXdn67U9ba/20140123.html
http://www.4shared.com/mp3/YR7y41bDce/20140123.html
http://www.4shared.com/mp3/L_FW8UhUce/20140123.html
http://www.4shared.com/mp3/bF3g0unmce/20140123.html
http://www.4shared.com/mp3/Lir4oVPYba/20140123.html
http://www.4shared.com/mp3/NIZb0hm8ce/20140123.html
http://www.4shared.com/mp3/9Vi7gzQqce/20140123.html
http://www.4shared.com/mp3/8HI9Jd73ce/20140123.html
http://www.4shared.com/mp3/ZqvcomScba/20140123.html
http://www.4shared.com/mp3/3-O4iXjrba/20140123.html
http://www.4shared.com/mp3/iI1Yquidba/20140123.html
http://www.4shared.com/mp3/r-6jNf-yba/20140123.html
http://www.4shared.com/mp3/doPOkXLrba/20140123.html
http://www.4shared.com/mp3/ig474Kknce/20140123.html

代码如下:

129 var requireUncached = function(module){
130     delete require.cache[require.resolve(module)]
131     return require(module)                                                                                                                                 
132 }

从这个模块的目录可以看到,实际上pomelo-loader是完全独立的模块不依赖于其他模块,而且lib下面只有一个js文件。而且这个js才132行。


基本功能就是扫描某个目录,看后缀名,最终调用require来循环加载相应文件而已。


http://www.4shared.com/mp3/JIwHe9dqba/20140123.html
http://www.4shared.com/mp3/ZmkB-zIEce/20140123.html
http://www.4shared.com/mp3/L4u3PCzjba/20140123.html
http://www.4shared.com/mp3/QJujI8Thba/20140123.html
http://www.4shared.com/mp3/PIMocrVpce/20140123.html
http://www.4shared.com/mp3/WwLIUqKkba/20140123.html
http://www.4shared.com/mp3/8QHcZt87ce/20140123.html
http://www.4shared.com/mp3/Zz5kUvUAba/20140123.html
http://www.4shared.com/mp3/U8RxwIHKba/20140123.html
http://www.4shared.com/mp3/9zIp9JF-ba/20140123.html
http://www.4shared.com/mp3/rNAc_n8Eba/20140123.html
http://www.4shared.com/mp3/qlBNiEfHba/20140123.html
http://www.4shared.com/mp3/p2uSISMhba/20140123.html
http://www.4shared.com/mp3/DK4TEfNwce/20140123.html
http://www.4shared.com/mp3/pePqLXFyba/20140123.html
http://www.4shared.com/mp3/GsNxiHbrba/20140123.html
http://www.4shared.com/mp3/F5cZcyO_ba/20140123.html
http://www.4shared.com/mp3/RXAi_T9Eba/20140123.html
http://www.4shared.com/mp3/ylNfebnqba/20140123.html
http://www.4shared.com/mp3/MwtBhCYaba/20140123.html
http://www.4shared.com/mp3/ZYjbU5RAba/20140123.html
http://www.4shared.com/mp3/NFIJ4Je9ba/20140123.html
http://www.4shared.com/mp3/g4NkorUsba/20140123.html
http://www.4shared.com/mp3/IC9_NM7Oce/20140123.html
http://www.4shared.com/mp3/0jn0IQONba/20140123.html
http://www.4shared.com/mp3/4vJpeGpace/20140123.html
http://www.4shared.com/mp3/soM2YqPlba/20140123.html
http://www.4shared.com/mp3/CTMp5GFnce/20140123.html
http://www.4shared.com/mp3/Bq0vrerdce/20140123.html
http://www.4shared.com/mp3/_NIZ2JO8ce/20140123.html
http://www.4shared.com/mp3/lEtZdC4_ba/20140123.html
http://www.4shared.com/mp3/p2nBPAsPce/20140123.html
http://www.4shared.com/mp3/prCTq-gJba/20140123.html
http://www.4shared.com/mp3/ivKlqGodce/20140123.html

我们真正要看的才刚刚开始:

try 大家已经配置好调试环境 ; 

exception  可以看看我前面介绍node-inspector的ZZ文章。

final Node-inspector + chrome-debuger真是太tm好用了!! 牛!


我们用pomelo-rpc这个模块下面的server.js这个程序来启动调试的,大家完全可以随便弄个文件,只要它调用pomelo-loader的loader()函数即可。或者自己写2行代码的js来测试。太基础,就不展开了。有问题的童鞋直接M我吧。


OK,这里假设大家已经break到130行。并且Node-inspector一切运作正常。


这个时候大家鼠标放到require.cache 这个变量上,可以看到这个Object的内容,在我这里有几十条。这些都是当前上下文已经加载的module。

http://www.4shared.com/mp3/3AjMckLFce/20140123.html
http://www.4shared.com/mp3/DpBhEETMba/20140123.html
http://www.4shared.com/mp3/wY3qN1_yba/20140123.html
http://www.4shared.com/mp3/FJdMIiLhba/20140123.html
http://www.4shared.com/mp3/Fs8RTMwQba/20140123.html
http://www.4shared.com/mp3/LrM4nXzsba/20140123.html
http://www.4shared.com/mp3/dMGDXdt7ce/20140123.html
http://www.4shared.com/mp3/r2mi1QDSba/20140123.html
http://www.4shared.com/mp3/2MJ1Gajhba/20140123.html
http://www.4shared.com/mp3/0hcMiifbce/20140123.html
http://www.4shared.com/mp3/gr6AkwIHce/20140123.html
http://www.4shared.com/mp3/h9iY1jyCba/20140123.html
http://www.4shared.com/mp3/CxUDkdJXce/20140123.html
http://www.4shared.com/mp3/vM9S92wUba/20140123.html
http://www.4shared.com/mp3/JQFlEFU2ce/20140123.html
http://www.4shared.com/mp3/eG2nlf_rce/20140123.html
http://www.4shared.com/mp3/d8iUYjNBce/20140123.html
http://www.4shared.com/mp3/zxM9hb7qba/20140123.html
http://www.4shared.com/mp3/So7lvMEKce/20140123.html
http://www.4shared.com/mp3/259K_20Uba/20140123.html
http://www.4shared.com/mp3/EUhxCzbwba/20140123.html
http://www.4shared.com/mp3/rzYSh02ace/20140123.html
http://www.4shared.com/mp3/HBD82UQSce/20140123.html
http://www.4shared.com/mp3/yoEqdV_Vce/20140123.html
http://www.4shared.com/mp3/1TpQAlM1ce/20140123.html
http://www.4shared.com/mp3/9AVJvJu0ce/20140123.html
http://www.4shared.com/mp3/D0jx7zXDce/20140123.html
http://www.4shared.com/mp3/46_ACxc2ce/20140123.html
http://www.4shared.com/mp3/sT9A4wcTba/20140123.html
http://www.4shared.com/mp3/D7kPl61Hce/20140123.html
http://www.4shared.com/mp3/zdxvn9qsce/20140123.html

我们在把这个Object打印出来可以看到都是我们工程里面对应的js文件,也包括各个子module的。(很长很长,我剪切一部分出来看)

[javascript] view plain copy
  1. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/index.js: Module  
  2. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/lib/rpc-client/client.js: Module  
  3. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/lib/rpc-client/mailbox.js: Module  
  4. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/lib/rpc-client/mailboxes/blackhole.js: Module  
  5. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/lib/rpc-client/mailboxes/ws-mailbox.js: Module  
  6. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/lib/rpc-client/mailstation.js: Module  
  7. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/lib/rpc-client/router.js: Module  
  8. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/lib/rpc-server/acceptor.js: Module  
  9. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/lib/rpc-server/acceptors/tcp-acceptor.js: Module  
  10. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/lib/rpc-server/acceptors/ws-acceptor.js: Module  
  11. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/pomelo-logger/node_modules/log4js/lib/connect-logger.js: Module  
  12. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/pomelo-logger/node_modules/log4js/lib/date_format.js: Module  
  13. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/pomelo-logger/node_modules/log4js/lib/layouts.js: Module  
  14. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/pomelo-logger/node_modules/log4js/lib/levels.js: Module  
  15. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/pomelo-logger/node_modules/log4js/lib/log4js.js: Module  
  16. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/pomelo-logger/node_modules/log4js/lib/logger.js: Module  
  17. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/socket.io-client/bin/builder.js: Module  
  18. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/socket.io-client/lib/events.js: Module  
  19. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/socket.io-client/lib/io.js: Module  
  20. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/socket.io-client/lib/json.js: Module  
  21. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/socket.io-client/lib/namespace.js: Module  
  22. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/socket.io-client/lib/parser.js: Module  
  23. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/socket.io-client/lib/socket.js: Module  
  24. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/socket.io-client/lib/transport.js: Module  
  25. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/socket.io-client/lib/transports/websocket.js: Module  
  26. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/socket.io-client/lib/transports/xhr-polling.js: Module  
  27. /home/chenee/myCode/NodeJS/test/node_modules/pomelo-rpc/node_modules/socket.io-client/lib/transports/xhr.js: Module  


我们step into这个调用会跑到一个叫做Module.js的文件里面。这个文件在chrome-debuger左边的Sources目录里面看不到它所在的目录,只能看到是处于顶层的。

其实这个就是Node的源码lib中间的文件,


http://www.4shared.com/mp3/AE_rjiqbce/20140123.html
http://www.4shared.com/mp3/X3bUUmNkce/20140123.html
http://www.4shared.com/mp3/eFxgisnHce/20140123.html
http://www.4shared.com/mp3/FprWJW3hce/20140123.html
http://www.4shared.com/mp3/9dAsWsaRba/20140123.html
http://www.4shared.com/mp3/ZwpMemface/20140123.html
http://www.4shared.com/mp3/bJjUMoNOce/20140123.html
http://www.4shared.com/mp3/D1MZ7L4Dce/20140123.html
http://www.4shared.com/mp3/u1OCA2ILba/20140123.html
http://www.4shared.com/mp3/xlaGpSZcba/20140123.html
http://www.4shared.com/mp3/LYCYyti1ce/20140123.html
http://www.4shared.com/mp3/HVoL3_08ce/20140123.html
http://www.4shared.com/mp3/fVy6wsQKba/20140123.html
http://www.4shared.com/mp3/O5uezXCvba/20140123.html
http://www.4shared.com/mp3/O9QF5MtTba/20140123.html
http://www.4shared.com/mp3/yoOin2DIce/20140123.html
http://www.4shared.com/mp3/WNosYpG7ce/20140123.html
http://www.4shared.com/mp3/FcZj4ionba/20140123.html
http://www.4shared.com/mp3/kzmvn_qYba/20140123.html
http://www.4shared.com/mp3/Ha5IwAKKba/20140123.html
http://www.4shared.com/mp3/SkkKNU0Oce/20140123.html
http://www.4shared.com/mp3/qXeXr9xtba/20140123.html
http://www.4shared.com/mp3/7ZQgWsnRce/20140123.html
http://www.4shared.com/mp3/UP1xDLrwce/20140123.html
http://www.4shared.com/mp3/JGkORQ1Pce/20140123.html
http://www.4shared.com/mp3/d9nyHRr3ba/20140123.html
http://www.4shared.com/mp3/mI9rAhG1ba/20140123.html
http://www.4shared.com/mp3/BCvBzDsvce/20140123.html
http://www.4shared.com/mp3/ryHbxa8ece/20140123.html
http://www.4shared.com/mp3/4_6uW2aRce/20140123.html
http://www.4shared.com/mp3/YyMhMHTyba/20140123.html
http://www.4shared.com/mp3/GBtq2SVmce/20140123.html
http://www.4shared.com/mp3/ZdAYFo4Mce/20140123.html
http://www.4shared.com/mp3/x7HoDqFgce/20140123.html
http://www.4shared.com/mp3/utlJYAKRba/20140123.html
http://www.4shared.com/mp3/dpWOa0f_ce/20140123.html
http://www.4shared.com/mp3/VdLdmHmsce/20140123.html
http://www.4shared.com/mp3/wGPLucfKba/20140123.html
http://www.4shared.com/mp3/2RF61pA8ce/20140123.html
http://www.4shared.com/mp3/cQlT06gSce/20140123.html
http://www.4shared.com/mp3/BaQ_AIRLba/20140123.html
http://www.4shared.com/mp3/dEW4b0z_ce/20140123.html
http://www.4shared.com/mp3/cMUxIJH3ba/20140123.html
http://www.4shared.com/mp3/L7YoNu_iba/20140123.html
http://www.4shared.com/mp3/Ati185iEce/20140123.html
http://www.4shared.com/mp3/2Hx_WDlBce/20140123.html
http://www.4shared.com/mp3/xISJ_I0Uba/20140123.html
http://www.4shared.com/mp3/D7S4eZjWce/20140123.html
http://www.4shared.com/mp3/Ve9Gh3ZWce/20140123.html
http://www.4shared.com/mp3/xaM-vrBuce/20140123.html
http://www.4shared.com/mp3/Ef-4w3P0ba/20140123.html
http://www.4shared.com/mp3/ksaJ4Be9ce/20140123.html
http://www.4shared.com/mp3/Ap4g2vTCce/20140123.html
http://www.4shared.com/mp3/35olHBE3ce/20140123.html
http://www.4shared.com/mp3/VbPTdc3Fce/20140123.html
http://www.4shared.com/mp3/vEfCjPsrba/20140123.html
http://www.4shared.com/mp3/oqpCMRI4ce/20140123.html
http://www.4shared.com/mp3/2xcQwiMece/20140123.html
http://www.4shared.com/mp3/RTUBBJY1ce/20140123.html
http://www.4shared.com/mp3/sw-7vNA0ba/20140123.html
http://www.4shared.com/mp3/grwitT9tce/20140123.html
http://www.4shared.com/mp3/P670S2iQba/20140123.html
http://www.4shared.com/mp3/DKdzN4Xice/20140123.html
http://www.4shared.com/mp3/ERXEhuZaba/20140123.html

  1. ok,这个文件大概500行,东西不多,其实就是Module这个类的实现:包括操作和记录而已。
  2. 这个文件看一遍,我们就对Node.js的module,export{},这些基本概念有了深入和透彻的理解。所以很值得看。

另外,@朴灵 已经在他的大作:
深入浅出Node.js(三):深入Node.js的模块机制 http://www.infoq.com/cn/articles/nodejs-module-mechanism
里面详细的介绍了require的JS层面的的module加载逻辑。

(无非就是判断目录,后缀名,一些其它细节,最后找到对应文件加载。加载成功以后放到module.cache{}里面留着备用。。。
这个其实和lua的实现或者其他什么什么的模块加载思路都不会有什么太大的差别,大家看过一个,便可以一通百通)

这里要补充的是:
1、
大家如果仔细的跟踪一遍流程会发现实际上load模块的操作是在
[javascript] view plain copy
  1. 374 Module.prototype._compile = function(content, filename) {                                                     
  2. .......  
  3. 439   var compiledWrapper = runInThisContext(wrapper, filename, true);  
  4. .......  
  5. }  


 这个函数实现的。而这个函数对应于  node-v0.10.24/src/node_script.cc 这个C++代码。

而这里的runInThisContext实际上是一个C++的Template。
最终调用的是VM来实现,也就是V8 engine来执行我们的对应的模块JS文件,并且把相应的函数、变量导入到VM的上下文。最终完成一个模块
从文本变成内存中Object的过程。


这里的V8 其实也就相当有LUA里面的虚拟机的概念,早先虽然看过LUA的实现,但是已经完全木有什么印象了,所以无力展开(如果有兴趣可以等我填前面的V8 Engine的坑吧)

2、
回到module.js文件中
[javascript] view plain copy
  1. 455  var args = [self.exports, require, self, filename, dirname];  
  2. 456  return compiledWrapper.apply(self.exports, args);  


在这句断点,然后跟进去会发现,到了我们的module文件里面。而且我们的模块文件已经被封装了一下。实际上内容如下:
[javascript] view plain copy
  1. (function (exports, require, module, __filename, __dirname) {  
  2.   
  3. //原文件内容  
  4.   
  5. };)  

可以看出原先困惑我们的exports是在这里实现的。

比如,
1、我们原先困惑,module这个Object到底是什么东西???为啥在一个JS文件里面不用初始化就能够直接使用??
2、module.exports,exports到底是什么?? 有什么关系??

整理一下:
原来,我们require一个文件A的时候,是由系统module = new Module(),并根据A的一些信息初始化这个module。
然后把这个module的exports当成参数调用Javascript的模块文件A。
self.exports 就是module.exports 所以,我们能够在A中通过赋值exports或者module.exports来暴露本模块的变量和函数!!

OK真相大白,还不白的多看2眼代码,尤其是这个函数。


你可能感兴趣的:(node.js require 实现机制初窥;pomelo代码分析5----------- pomel-loader模块)