欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解小程序循環(huán)require之坑

 更新時(shí)間:2019年03月08日 09:42:28   作者:沒有角的牛  
這篇文章主要介紹了詳解小程序循環(huán)require之坑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1. 循環(huán)require

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

// a.js
const B = require('./b.js');

console.log('B in A', B);
const A = {
  name: 'A',
  childName: B.name,
};
module.exports = A;

// b.js
const C = require('./c.js');

console.log('C in B', C);
const B = {
  name: 'B',
  childName: C.name,
}
module.exports = B;

// c.js
const A = require('./a.js');

console.log('A in C', A);
const C = {
  name: 'C',
  childName: A.name,
};
module.exports = C;

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

2. 小程序中的坑

在正常情況下,JS引擎是可以解析循環(huán)require的情形的。但是在一些低版本的小程序中,居然出現(xiàn)程序一直循環(huán)require的情況,最終導(dǎo)致棧溢出而報(bào)錯(cuò),實(shí)在是天坑。

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

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);
}

/**
 * 遞歸函數(shù),解析文件的依賴
 * @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 '';
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論