fcp-js.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /**
  2. * 注册命名空间:baidu.js
  3. */
  4. baidu.namespace.register("baidu.js");
  5. /**
  6. * js相关处理
  7. * @author zhaoxianlie
  8. */
  9. baidu.js = (function(){
  10. var _readyQueen = null;
  11. var _asyncInterface = 0;
  12. var _scriptBlockCount = 0;
  13. /**
  14. * js源代码
  15. * @item {fileName:'',fileContent:''}
  16. */
  17. var _rawJsSource = [];
  18. /**
  19. * 页面cookies
  20. */
  21. _cookies = [];
  22. /**
  23. * 结果集
  24. */
  25. var _summaryInformation = null;
  26. /**
  27. * 初始化js文件的读取队列
  28. * @param {Object} isFinished 是否读取完成
  29. */
  30. var _initReadyQueen = function(isFinished){
  31. _readyQueen = {
  32. curIndex : 0, //当前正处于读取的index
  33. queen : [], //js文件队列,格式为:{src:"",block:""},其中src和block不可能同时有值
  34. callback : new Function(), //回调方法
  35. finished : isFinished //是否读取完成
  36. };
  37. };
  38. /**
  39. * 增加一项读取项
  40. * @param {Object} readyItem 格式为:{src:Object,block:Object}
  41. */
  42. var _addReadyItem = function(readyItem){
  43. _readyQueen.queen.push(readyItem);
  44. };
  45. /**
  46. * 获取当前正在解析的script块
  47. */
  48. var _getCurrentReadyItem = function(){
  49. return _readyQueen.queen[_readyQueen.curIndex];
  50. };
  51. /**
  52. * 判断当前读取的是否为最后一个script块
  53. */
  54. var _isLastReadyItem = function(){
  55. return (_readyQueen.curIndex == _readyQueen.queen.length);
  56. };
  57. /**
  58. * 读取队列移动到下一个元素
  59. */
  60. var _moveToNextReadyItem = function(){
  61. _readyQueen.curIndex += 1;
  62. };
  63. /**
  64. * 判断当前队列是否读取完毕
  65. */
  66. var _isDealFinished = function(){
  67. return _readyQueen.finished;
  68. };
  69. /**
  70. * 根据文件路径,提取文件名
  71. * @param {Object} path 文件url
  72. */
  73. var _getFileName = function(path){
  74. var reg = /(.*\/)([^\/]+\.js)/;
  75. var p = reg.exec((path || '').replace(/\?.*/,''));
  76. return p ? p[2] : path ? ('异步接口' + ++_asyncInterface) : ('script块' + ++_scriptBlockCount);
  77. };
  78. /**
  79. * 初始化侦测结果
  80. */
  81. var _initSummaryInformation = function(){
  82. _summaryInformation = {
  83. cookies: [], //有效的cookie,[{key:'',value:''}]
  84. scriptTag : {
  85. scriptBlock:0, //页面上的<script type="text/javascript"></script>数量
  86. scriptSrc:0 //页面上的<script type="text/javascript" src=""></script>数量
  87. },
  88. domain : false, //document是否设置了domain,设置了则domain值为document.domain
  89. jsMinified : { //js文件是否被压缩
  90. files : [],
  91. count : 0
  92. },
  93. tangram : [], //页面上引用的tangram
  94. duplicatedFiles : [] //重复的文件
  95. };
  96. };
  97. /**
  98. * 保存JS代码
  99. * @param {Object} _filePath 文件完整路径
  100. * @param {Object} _fileContent 内容
  101. */
  102. var _saveJsSource = function(_filePath,_fileContent){
  103. //过滤CSS注释
  104. _fileContent = _fileContent.replace(/\/\*[\S\s]*?\*\//g,'');
  105. //提取文件名
  106. var _fileName = _getFileName(_filePath);
  107. _rawJsSource.push({
  108. href : _filePath ? _filePath : '#',
  109. fileName : _fileName,
  110. fileContent : _fileContent
  111. });
  112. };
  113. /**
  114. * 将scripts归类进行检测
  115. * @param {Array} scripts Script对象数组
  116. */
  117. var _getJsData = function(scripts){
  118. //从页面上获取<script src> 或者 <script> 内容
  119. var jsdata = (function(){
  120. var ss = {src:[],block:[]};
  121. jQuery.each(scripts,function(i,script){
  122. //通过 <script src> 标签引用的js
  123. if(!!script.src) { ss.src.push(script); }
  124. //通过 <script> 标签定义的js
  125. else if(!!script.innerHTML) { ss.block.push(script); }
  126. });
  127. return ss;
  128. })();
  129. return jsdata;
  130. };
  131. /**
  132. * 提取JS文件内容
  133. * @param {String} src 需要读取的js文件
  134. * @see 具体可参见network.js文件中定义的Function: _readFileContent
  135. */
  136. var _getJsSourceByServer = function(link){
  137. //向background发送一个消息,要求其加载并处理js文件内容
  138. chrome.extension.sendMessage({
  139. type : MSG_TYPE.GET_JS,
  140. link : link.src
  141. },function(respData){
  142. //保存源代码
  143. _saveJsSource(respData.path,respData.content)
  144. //继续读取(是从就绪队列中进行读取)
  145. _readRawJs();
  146. });
  147. };
  148. /**
  149. * 读取页面上已经存在的<script>标签内的js
  150. * @param {script} script
  151. * @return {Undefined} 无返回值
  152. */
  153. var _readScriptTagContent = function(script){
  154. //保存源代码
  155. _saveJsSource('',script.innerHTML)
  156. //继续读取(是从就绪队列中进行读取)
  157. _readRawJs();
  158. };
  159. /**
  160. * 从就绪队列中,逐个加载js
  161. */
  162. var _readRawJs = function(){
  163. //取得当前需要读取的数据
  164. var curData = _getCurrentReadyItem();
  165. //是否读取完成
  166. if(_isDealFinished() || !curData) {
  167. chrome.extension.sendMessage({
  168. type : MSG_TYPE.JS_READY
  169. });
  170. return;
  171. }
  172. //_readyQueen.curIndex是会被累加的
  173. _moveToNextReadyItem();
  174. //清空队列
  175. if(_isLastReadyItem()) {
  176. _initReadyQueen(true);
  177. }
  178. //如果是<script>标签
  179. if(!!curData.block) {
  180. _readScriptTagContent(curData.block);
  181. }
  182. //如果是<script src>标签
  183. else if(!!curData.src){
  184. _getJsSourceByServer(curData.src);
  185. }
  186. };
  187. /**
  188. * 初始化JS数据
  189. */
  190. var _initJsData = function(){
  191. scripts = _getJsData(document.scripts);
  192. //处理<script>定义的样式
  193. if(scripts.block && scripts.block.length >0) {
  194. jQuery.each(scripts.block,function(i,script){
  195. //加入读取队列
  196. _addReadyItem({src:null,block:script});
  197. });
  198. }
  199. //处理<script src>引入的js文件
  200. if(scripts.src && scripts.src.length >0) {
  201. jQuery.each(scripts.src,function(i,src){
  202. //加入读取队列
  203. _addReadyItem({src:src,block:null});
  204. });
  205. }
  206. //开始读取
  207. _readRawJs();
  208. };
  209. /**
  210. * 对以存储的js代码进行解析
  211. */
  212. var _dealJsFile = function(){
  213. var isStop = false;
  214. jQuery.each(_rawJsSource,function(i,fileObj){
  215. _dealJs(fileObj);
  216. });
  217. _summaryInformation.scriptTag = {
  218. scriptSrc : jQuery('script[src]').length,
  219. scriptBlock : jQuery('script:not(script[src])').length
  220. };
  221. };
  222. /**
  223. * 处理某个js文件内的js
  224. * @param {Object} _fileObj
  225. * @config {String} fileName
  226. * @config {String} fileContent
  227. */
  228. var _dealJs = function(_fileObj){
  229. var fileName = _fileObj.fileName;
  230. var fileContent = _fileObj.fileContent;
  231. //检测js是否压缩
  232. _detectJsMinify(_fileObj);
  233. };
  234. /**
  235. * 获取浏览器记录的Cookie
  236. */
  237. var _getCookies = function(){
  238. chrome.extension.sendMessage({
  239. type : MSG_TYPE.GET_COOKIE,
  240. url : location.href
  241. },function(respData){
  242. _cookies = respData.cookie;
  243. });
  244. };
  245. /**
  246. * 侦测页面的cookie
  247. */
  248. var _detectCookies = function(){
  249. //cookie已经在_getCookies中准备好了
  250. _summaryInformation.cookies = _cookies;
  251. };
  252. /**
  253. * 检测某个js文件是否被压缩
  254. * @param {Object} jsObj js文件对象
  255. * @config {String} href 文件路径
  256. * @config {String} fileName 文件名
  257. * @config {String} fileContent 文件内容
  258. */
  259. var _detectJsMinify = function(jsObj){
  260. var lines = jsObj.fileContent.split(/\n/);
  261. var average_length_perline = jsObj.fileContent.length / lines.length;
  262. if (average_length_perline < 150 && lines.length > 1) {
  263. _summaryInformation.jsMinified.count++;
  264. _summaryInformation.jsMinified.files.push({
  265. href : jsObj.href,
  266. fileName : jsObj.fileName
  267. });
  268. }
  269. };
  270. /**
  271. * 检测tangram
  272. */
  273. var _detectTangram = function(){
  274. var allScripts = document.querySelectorAll('script[src]');
  275. var tangram = [];
  276. jQuery.each(allScripts,function(i,item){
  277. if(!item.src) return true;
  278. var _fileName = _getFileName(item.src);
  279. if(_fileName.indexOf('tangram') > -1) {
  280. tangram.push(_fileName);
  281. }
  282. });
  283. _summaryInformation.tangram = tangram;
  284. };
  285. /**
  286. * 检测是否引入的重复的文件
  287. */
  288. var _detectDuplicatedFile = function(){
  289. scripts = _getJsData(document.scripts);
  290. var files = {};
  291. var duplicatedFiles = [];
  292. var dealedFiles = {};
  293. //处理<script>引入的js文件
  294. if(scripts.src && scripts.src.length >0) {
  295. jQuery.each(scripts.src,function(i,link){
  296. files[link.src] = parseInt(files[link.src] || 0,10) + 1;
  297. });
  298. jQuery.each(files,function(href,count){
  299. //文件src重复
  300. if(count > 1) {
  301. duplicatedFiles.push({
  302. href : href,
  303. count : count
  304. });
  305. } else { //href不重复的情况下,检测文件内容是否相同
  306. var _fileContent = '';
  307. var _dupFiles = [];
  308. jQuery.each(_rawJsSource,function(i,file){
  309. if(file.href == href) {
  310. _fileContent = file.fileContent.replace(/\s+/g,'');
  311. return false;
  312. }
  313. });
  314. jQuery.each(_rawJsSource,function(i,file){
  315. if(_fileContent == file.fileContent.replace(/\s+/g,'') && !dealedFiles[file.href] && _dupFiles.join(',').indexOf(file.href) == -1) {
  316. _dupFiles.push(file.href);
  317. }
  318. });
  319. if(_dupFiles.length > 1) {
  320. duplicatedFiles.push({
  321. href : href,
  322. dupFiles : _dupFiles
  323. });
  324. dealedFiles[href] = true;
  325. }
  326. }
  327. });
  328. }
  329. _summaryInformation.duplicatedFiles = duplicatedFiles;
  330. };
  331. /**
  332. * 检测Js
  333. */
  334. var _detectJS = function(){
  335. //处理js文件以及script块
  336. _dealJsFile();
  337. };
  338. /**
  339. * 初始化
  340. */
  341. var _init = function(){
  342. //初始化就绪队列
  343. _initReadyQueen(false);
  344. //初始化JS数据
  345. _initJsData();
  346. //初始化cookie
  347. _getCookies();
  348. };
  349. /**
  350. * js相关的侦测
  351. * @param {Function} callback 侦测完毕后的回调方法,形如:function(data){}
  352. * @config {Object} data 就是_summaryInformation
  353. */
  354. var _detect = function(callback){
  355. //初始化结果集
  356. _initSummaryInformation();
  357. //cookie侦测
  358. _detectCookies();
  359. //侦测页面上script标签
  360. _detectJS();
  361. //tangram检测
  362. _detectTangram();
  363. //重复文件检测
  364. _detectDuplicatedFile();
  365. //执行回调
  366. callback.call(null,_summaryInformation);
  367. };
  368. return {
  369. init : _init,
  370. detect : _detect,
  371. getCookies : _getCookies
  372. };
  373. })();