国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

詳解小程序循環require之坑

2019-11-19 12:01:21
字體:
來源:轉載
供稿:網友

1. 循環require

在JavaScript中,模塊之間可能出現相互引用的情況,例如現在有三個模塊,他們之間的相互引用關系如下,大致的引用關系可以表示為 A -> B -> C -> A,要完成模塊A,它依賴于模塊C,但是模塊C反過來又依賴于模塊A,此時就出現了循環require。

// a.jsconst B = require('./b.js');console.log('B in A', B);const A = {  name: 'A',  childName: B.name,};module.exports = A;
// b.jsconst C = require('./c.js');console.log('C in B', C);const B = {  name: 'B',  childName: C.name,}module.exports = B;
// c.jsconst A = require('./a.js');console.log('A in C', A);const C = {  name: 'C',  childName: A.name,};module.exports = C;

那JS引擎會一直循環require下去嗎?答案是不會的,如果我們以a.js為入口執行程序,C在引用A時,a.js已經執行,不會再重新執行a.js,因此c.js獲得的A對象是一個空對象(因為a.js還沒執行完成)。

2. 小程序中的坑

在正常情況下,JS引擎是可以解析循環require的情形的。但是在一些低版本的小程序中,居然出現程序一直循環require的情況,最終導致棧溢出而報錯,實在是天坑。

那如何解決呢,很遺憾,目前并未找到完美的方法來解決,只能找到程序中的循環require的代碼,并進行修改。為了快速定位程序中的循環引用,寫了一段NodeJs檢測代碼來檢測進行檢測。

const fs = require('fs');const path = require('path');const fileCache = {};const requireLink = [];if (process.argv.length !== 3) { console.log(`please run as: node ${__filename.split(path.sep).pop()} file/to/track`); return;}const filePath = process.argv[2];const absFilePath = getFullFilePath(filePath);if (absFilePath) { resolveRequires(absFilePath, 0);} else { console.error('file not exist:', filePath);}/** * 遞歸函數,解析文件的依賴 * @param {String} file 引用文件的路徑 * @param {Number} level 文件所在的引用層級 */function resolveRequires(file, level) { requireLink[level] = file; for (let i = 0; i < level; i ++) {  if (requireLink[i] === file) {   console.log('**** require circle detected ****');   console.log(requireLink.slice(0, level + 1));   console.log();   return;  } } const requireFiles = getRequireFiles(file); requireFiles.forEach(file => resolveRequires(file, level + 1));}/** * 獲取文件依賴的文件 * @param {String} filePath 引用文件的路徑 */function getRequireFiles(filePath) { if (!fileCache[filePath]) {  try {   const fileBuffer = fs.readFileSync(filePath);   fileCache[filePath] = fileBuffer.toString();  } catch(err) {   console.log('read file failed', filePath);   return [];  } } const fileContent = fileCache[filePath]; // 引入模塊的幾種形式 const requirePattern = /require/s*/(['"](.*?)['"]/)/g; const importPattern1 = /import/s+.*?/s+from/s+['"](.*?)['"]/g; const importPattern2 = /import/s+['"](.*?)['"]/g; const requireFilePaths = []; const baseDir = path.dirname(filePath); let match = null; while ((match = requirePattern.exec(fileContent)) !== null) {  requireFilePaths.push(match[1]); } while ((match = importPattern1.exec(fileContent)) !== null) {  requireFilePaths.push(match[1]); } while ((match = importPattern2.exec(fileContent)) !== null) {  requireFilePaths.push(match[1]); } return requireFilePaths.map(fp => getFullFilePath(fp, baseDir)).filter(fp => !!fp);}/** * 獲取文件的完整絕對路徑 * @param {String} filePath 文件路徑 * @param {String} baseDir 文件路徑的相對路徑 */function getFullFilePath(filePath, baseDir) { if (baseDir) {  filePath = path.resolve(baseDir, filePath); } else {  filePath = path.resolve(filePath); } if (fs.existsSync(filePath)) {  const stat = fs.statSync(filePath);  if (stat.isDirectory() && fs.existsSync(path.join(filePath, 'index.js'))) {   return path.join(filePath, 'index.js');  } else if (stat.isFile()){   return filePath;  } } else if (fs.existsSync(filePath + '.js')) {  return filePath + '.js'; } return '';}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 柘荣县| 子长县| 耿马| 安图县| 随州市| 江城| 桃江县| 葫芦岛市| 彝良县| 吕梁市| 蛟河市| 长白| 南郑县| 古丈县| 普安县| 昭通市| 贵州省| 碌曲县| 息烽县| 石楼县| 淅川县| 通化市| 增城市| 体育| 襄城县| 平定县| 汉源县| 高尔夫| 虹口区| 将乐县| 松阳县| 和硕县| 渭南市| 新河县| 沐川县| 来安县| 平江县| 二手房| 伊春市| 西华县| 襄城县|