详解小程序循环require之坑
1.循环require
在JavaScript中,模块之间可能出现相互引用的情况,例如现在有三个模块,他们之间的相互引用关系如下,大致的引用关系可以表示为A->B->C->A,要完成模块A,它依赖于模块C,但是模块C反过来又依赖于模块A,此时就出现了循环require。
//a.js
constB=require('./b.js');
console.log('BinA',B);
constA={
name:'A',
childName:B.name,
};
module.exports=A;
//b.js
constC=require('./c.js');
console.log('CinB',C);
constB={
name:'B',
childName:C.name,
}
module.exports=B;
//c.js
constA=require('./a.js');
console.log('AinC',A);
constC={
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检测代码来检测进行检测。
constfs=require('fs');
constpath=require('path');
constfileCache={};
constrequireLink=[];
if(process.argv.length!==3){
console.log(`pleaserunas:node${__filename.split(path.sep).pop()}file/to/track`);
return;
}
constfilePath=process.argv[2];
constabsFilePath=getFullFilePath(filePath);
if(absFilePath){
resolveRequires(absFilePath,0);
}else{
console.error('filenotexist:',filePath);
}
/**
*递归函数,解析文件的依赖
*@param{String}file引用文件的路径
*@param{Number}level文件所在的引用层级
*/
functionresolveRequires(file,level){
requireLink[level]=file;
for(leti=0;iresolveRequires(file,level+1));
}
/**
*获取文件依赖的文件
*@param{String}filePath引用文件的路径
*/
functiongetRequireFiles(filePath){
if(!fileCache[filePath]){
try{
constfileBuffer=fs.readFileSync(filePath);
fileCache[filePath]=fileBuffer.toString();
}catch(err){
console.log('readfilefailed',filePath);
return[];
}
}
constfileContent=fileCache[filePath];
//引入模块的几种形式
constrequirePattern=/require\s*\(['"](.*?)['"]\)/g;
constimportPattern1=/import\s+.*?\s+from\s+['"](.*?)['"]/g;
constimportPattern2=/import\s+['"](.*?)['"]/g;
constrequireFilePaths=[];
constbaseDir=path.dirname(filePath);
letmatch=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]);
}
returnrequireFilePaths.map(fp=>getFullFilePath(fp,baseDir)).filter(fp=>!!fp);
}
/**
*获取文件的完整绝对路径
*@param{String}filePath文件路径
*@param{String}baseDir文件路径的相对路径
*/
functiongetFullFilePath(filePath,baseDir){
if(baseDir){
filePath=path.resolve(baseDir,filePath);
}else{
filePath=path.resolve(filePath);
}
if(fs.existsSync(filePath)){
conststat=fs.statSync(filePath);
if(stat.isDirectory()&&fs.existsSync(path.join(filePath,'index.js'))){
returnpath.join(filePath,'index.js');
}elseif(stat.isFile()){
returnfilePath;
}
}elseif(fs.existsSync(filePath+'.js')){
returnfilePath+'.js';
}
return'';
}
 
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。