详解小程序循环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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。