1.autojs之lua
2.systemtap从入门到放弃(一)
3.带tap是什么意思?
4.systemtap安装SystemTap
5.SystemTapå·¥å
·ç使ç¨åºç¡
6.systemtap使用指南
autojs之lua
在autojs中使用lua能提升自动化脚本的灵活性和功能。为了实现这一目标,依赖于一个名为luaJ的java实现的lua脚本解释器。下面将逐步展示如何在autojs中集成lua,以及实现的步骤和效果展示。
首先,pythony源码导入luaJ类,这是实现lua脚本运行的基础。确保在项目中正确导入此类,以利用luaJ的解释功能。
接下来,创建一个Globals对象,用于管理全局状态。通过这个对象,可以轻松地在脚本中访问和设置全局变量,使脚本的使用更加灵活。
之后,执行lua文件成为关键步骤。通过加载lua文件并调用其中的函数或执行指令,可以实现自动化的任务,如模拟用户操作、自动化数据处理等。
获取lua变量的值,是进一步操作的基础。这允许根据脚本中的逻辑,动态地访问和使用变量,从而实现复杂的功能。
还有一种运行lua脚本的方式,即通过直接执行lua代码,而非加载文件。这种方式适合编写和执行简短的脚本,或在脚本执行过程中动态生成代码。
在实际应用中,一个典型的lua代码示例可以是自动化点击操作。通过编写简单的脚本,可以模拟用户点击屏幕上的特定位置,实现自动化任务。多点触摸钢琴源码
完整源码示例如下:
lua
Globals.set('clickPosition', { x: , y: })
function doClick()
local position = Globals.get('clickPosition')
TouchAction(device).tap({ x: position.x, y: position.y}).perform()
end
以上源码展示了如何在autojs中集成lua,通过导入luaJ类、创建全局变量、执行lua代码来实现自动化功能。使用这种方法,可以极大地提升自动化脚本的效率和可扩展性。
systemtap从入门到放弃(一)
内核调试利器:systemtap从入门到放弃(一)
systemtap,一个用于简化Linux系统运行形态信息收集的开源工具,立足于性能诊断与bug调试。相较于繁琐的工具、耗时的重新编译与引导过程,systemtap以动态hook内核代码的特性,提供了便捷的解决方案。其工作原理与底层kprobe接口紧密相连,通过在kprobe基础上引入脚本解析与内核模块编译运行单元,使开发人员得以在应用层实现对内核的hook,简化了开发流程。
相比传统的kernel API与debugfs接口,systemtap提供了更加简洁的命令行接口与内核指令脚本语言,对于开发者而言,它成为了一款极其实用的工具,尤其在bug调试、性能分析与源码学习方面。
入门systemtap,首先需了解其独特的脚本语法。脚本的编写,就是找到所需事件并设计事件处理流程的过程。系统中常用的语法元素包括脚本命名、注释、变量、数组、条件语句与循环等。其中,变量作用域默认为函数或括号内,全局变量则需在函数外显式声明。数组与关联数组则提供了数据存储与访问的华为商城前端源码灵活性。
在systemtap中,通过探针(probe)来触发事件处理,支持对特定内核函数、模块函数进行探测。此外,systemtap还提供了一系列内置探针(tapset),开发者可直接调用,加速调试与分析工作。
系统中常见的可探测事件包括函数调用、异常处理、系统调用等,这些事件为开发者提供了丰富的调试切入点。通过精心设计的脚本,开发者能够精准捕捉并分析系统行为,优化性能,定位并解决bug。
systemtap的脚本语言简洁易懂,对于底层开发人员而言,学习曲线相对平缓。然而,掌握其脚本语法与内置探针的使用,对于深入应用systemtap,实现高效、精确的调试至关重要。
综上所述,systemtap凭借其独特的功能与简洁的语法,为Linux内核调试提供了一种高效、便捷的工具。从入门到掌握,开发者需深入理解其工作原理与脚本语言,灵活应用内置探针,以实现精准的系统调试与优化。
带tap是什么意思?
在技术领域,tap代表着一种调试协议的名称。tap调试协议可以使调试者连接到目标设备上的调试接口,进而进行源码级别的影视源码怎么复制调试和管理。它是一种简单、高效的调试协议,被广泛应用于软件调试和开发中。
在软件调试中,tap的主要意义是提供了一种可视化的、实时的调试手段。通过连接调试器和目标设备,调试者可以随时随地对目标设备中的程序进行调试、查看、修改,从而更好地发现问题并解决它们。同时,tap还能简化调试工作流程,提升开发效率。
tap调试协议可适用于不同的操作系统和开发环境。例如,在嵌入式系统开发中,tap常被应用于ARM架构的芯片和微控制器上,为嵌入式程序的调试和开发提供支持。而在PC端应用开发中,tap则主要应用于C/C++编程语言,可以与各种不同的集成开发环境(IDE)相兼容。总而言之,tap在软件开发、调试领域的应用非常广泛,对提升程序质量和开发效率都起到了积极的作用。
systemtap安装SystemTap
在开始安装SystemTap之前,确保你的系统已经安装了两个关键软件包:kernel-debuginfo RPM和elfutils RPM。kernel-debuginfo是SystemTap依赖于内核调试信息的工具,大多数发行版并未预装,需要从相应的下载站点获取。 elfutils RPM则为SystemTap提供了分析调试信息所需的库函数。推荐安装elfutils-0.或更高版本,目前最新版本为0.-0.1。如果系统中没有,可以访问SystemTap的天气公众号源码官方网站下载RPM包或源代码进行升级。 安装SystemTap有RPM包和源码编译两种途径。对于Fedora Core 6用户,系统自带的systemtap可能已经足够,无需额外安装。而对于其他需要源码编译的情况,步骤如下:首先,从SystemTap FTP站点下载最新的源码包:/root > tar -jxf SystemTap
然后,切换到源码目录:/root > cd src
执行配置步骤:/root/src> ./configure
开始编译:/root/src> make
最后,安装SystemTap:/root/src> make install
请根据你的系统需求和环境,选择合适的安装方法。确保所有依赖已准备就绪,以顺利完成SystemTap的安装过程。SystemTapå·¥å ·ç使ç¨åºç¡
æ¥çå½åå æ ¸çæ¬æ¯åªä¸ä¸ªï¼ç¶å使ç¨æ¾å°å æ ¸æ建ç详ç»ä¿¡æ¯ï¼ç¶åå»å¯¹åºåå¸ç½ç«ä¸æ¾kernel-debuginfoåkernel-debuginfo-commonå ã
å®æå®è£ åå¯ä»¥éè¿ä¸é¢å½ä»¤æµè¯systemtap
è¿è¡æµè¯ï¼ççsystemtapææ å®è£ æåã
ä¸é¢å½ä»¤æ¼ç¤ºæ¥ç__lookup_hash()å½æ°è¿åæ¶å»å¯ä»¥æ¥çå°çåé
å¨ä¸è¡¨ä¸æ¾ç¤ºäºlookup_hashå¨æ件ä¸çè¡å·ï¼æ¾ç¤ºäºå为$return çåéï¼å ¶å®è¿ä¸ªreturnåéå°±æ¯systemtap表示å½æ°è¿åå¼çãè$name,$base,$flagæ们对çlinuxæºç çåç°è¿æ¯__lookup_hashçä¸ä¸ªå ¥åã
ä¸é¢å½ä»¤å¯ä»¥æ¥ç__lookup_hashå½æ°å ¥å£å¯ä»¥æ¥ççåé
ä¹å¯ä»¥éè¿statementæ¹å¼æ¥çå æ ¸ç¬¦å·è¡¨éæç__lookup_hashç¸å ³çè¡
å¦ææ¥æ¾çå æ ¸å½æ°ä½äºæ个模åéå¯ä»¥ä½¿ç¨ä¸é¢å½ä»¤ï¼
éè¿ä¸é¢å½ä»¤å¯ä»¥æ¥çå°æ个æ£å¨è¿è¡çè¿ç¨çå½æ°
ä¸ä¾ä¸çå°æ¾å°äºsyscall.Mountå½æ°ï¼å¹¶ä¸æå®çææåæ°ååæ°ç±»åé½æå°äºåºæ¥ã
åé¢å¯ä»¥å¨stapèæ¬ä¸ï¼è¿ä¸ªå½æ°çä¸ä¸æéç´æ¥ä½¿ç¨è¿äºåæ°ï¼ä¾å¦éè¿$sourceå¯ä»¥è®¿é®å°åæ°source
systemtapæ¯æprint()åprintf()å½æ°ï¼å ¶ä¸printf使ç¨è¯æ³åcè¯è¨ä¸è´ãæ¯æ%sï¼%dï¼%xæ ¼å¼
å¨systemtapéå¡æ¯ä»¥$å¼å¤´çåéé½æ¯ç®æ åéï¼å¦æç®æ åéç»æä½æéæè ç»æä½å¯¹è±¡ï¼é£ä¹å¯ä»¥ä½¿ç¨->ç´æ¥è®¿é®å ¶æåãä¾å¦ä¸ä¾ä¸ï¼
常è§æ åµä¸ï¼printfï¼ï¼æå°targetåéæ¶å»ï¼åªæå°å ¶å¼ãå¦æéè¦å°å ¶æåï¼æéç±»åçtargetéè¦å°å ¶æåç对象çæåå±å¼ï¼å¯ä»¥å¨targetåéåé¢å $çæ¹å¼ä¾å¦ï¼
ä¸è¬æ åµä¸å¯¹structçå±å¼åªä¼å°æåå¼ä¸çº§ï¼å¦æç¸å¯¹æåå é¨ç»§ç»å±å¼å¯ä»¥å¨ç®æ åéåé¢è·$$
å¨systemtapä¸æ¯æé»è¾ifè¯å¥æ ¼å¼ä¸ºï¼
é»è¾è¯å¥æ¯æ以ä¸æ¯è¾
==ï¼!=,>=,>,<,<=
ä¸è¿°ä¾å对ls -lä¸çxmallocè¿è¡å æ å溯ï¼
-d å¯æ§è¡æ件å
--ldd ææå ±äº«åº
-c âls -lâ æ§è¡çåè¿ç¨ä½
ä¸é¢ä¾åå°æå°__lookup_hashä¸returnè¿ådentry*éinodeæåçi_inoåæå
è¿ä¸ä¾åä¸-o zxy.txtçææå°±æ¯å°ç»æåå ¥æ件zxy.txtä¸ï¼é»è®¤è¾åºå°æ§å¶å°ï¼
ä¸é¢ä¾åå°å¨å æ ¸ä¸ä½¿ç¨å¼ºå¶ç±»å转æ¢
è¿é解éä¸ä¸ï¼å æ ¸ä¸æ¹æ³å¼ºå¶è½¬æ¢
å¨ç¨systemtapè·è¸ªå æ ¸æ¶ä½¿ç¨å æ æå°å½ä»¤ï¼å¸¸å¸¸æå°ä¸åºæ¥å¦å¤æ¨¡åçå½æ°ï¼è¿æ¯å 为è¿äºæ¨¡å没æ被å è½½ãå¯ä»¥å¨systemtapå¯å¨å½ä»¤ä½¿ç¨--all-modules æ¹æ³å¼ºå¶å°ææ模å符å·å 载起æ¥ã
ä¸é¢ä¾å对ç¨golangåçdockerdè¿ç¨syscall.Mountè°ç¨å ¥å£æ¶å»æå°syscall.Mountï¼ï¼å½æ°çåæ°
sourceçstringå段å 容
ä¸é¢ä¾åæå°golangåçdockerdè¿ç¨xxx.Getå½æ°è¿åæ¶å»çåæ°æ åµ
}
systemtap对golangæ¯æä¸å¤å®ç¾ï¼ç¨æ·éè¦èªå·±è§£æåºæ¬ç»æä¾å¦golangçstringï¼arrayåsliceè¿äºé½éè¦ç¨æ·èªå·±è§£æãstring被systemtapè¯å«ä¸ºstruct string,æ¤ç»æsystemtapå¯ä»¥è¯å«çå®ä¹å¯ä»¥ç®å为ï¼
éè¦æ³¨æçæ¯éè¿systemtapæå°golang stringçstring->strä¼å¤æå¾å¤å符ï¼å 为stringæåstr并éæç §cè¯è¨å®ä¹çå符串以\0表示å符串ç»æï¼æ们åªè½ç»åstringçå段lenæ¥è·å精确çå符串å 容
sliceå®å ¨ä¸è¢«systemtapè¯å«ï¼æ们å¯ä»¥å°systemtapå¯ä»¥è¯å«çsliceç®å为æ¤ç§å®ä¹ï¼
å ¶ä¸arrayå°±æ¯æåsliceåå¨åå çé¦å°åã
è¦æ¯æ们æ³è·åhelo=[]string{ âhelloâ,âworldâ}è¿æ ·çå符串sliceçå 容å¯ä»¥éè¿systemtapæä¾ç@cast(addrï¼âtypeâ,âfileâ)å½æ°å°æ个å°å强转为fileä¸å®ä¹çtypeç»æãå ·ä½æ¥è¯´å¯ä»¥å¦ä¸åè·åhelloçå 容
systemtap使用指南
Systemtap 是一种工具,用于开发人员和管理员编写和复用简单脚本以深入检查 Linux 系统活动。它允许快速提取、过滤和汇总数据,安全地诊断复杂性能或功能问题。
使用 Systemtap,最简单的探测类型是跟踪一个事件,例如在 open 系统调用执行时打印特定进程信息及参数。
Systemtap 支持多种内置事件,并可自定义额外事件,这些事件通过统一命名的点分隔参数化标识符语法定义。编写脚本时,需指定探测位置及打印内容。
Systemtap 的脚本通过翻译成 C 代码并运行系统 C 编译器来创建内核模块,模块在内核中激活所有探测事件。模块加载时,探测到的事件触发编译的处理程序运行。
跟踪事件的处理程序可以使用丰富控制结构,类似于 awk 语法,用于描述算法。脚本支持条件语句,允许限制跟踪或逻辑特定于进程或感兴趣的地方。
Systemtap 脚本可以使用变量、表达式和函数,支持 C 和 awk 风格的语法,以及字符串和数字运算。全局变量和特殊“目标变量”用于访问探测点上下文。
目标变量允许访问内核源代码中的值,并提供如地址、结构打印、变量范围和类型转换功能。全局变量用于在探测程序之间共享数据。
脚本还可以包含自定义函数,定义在脚本中的任何位置,并接受字符串或数字参数,返回单个字符串或数字。
Systemtap 提供关联数组,用于在不同探测程序之间共享数据,数组实现为哈希表,并且必须声明为全局变量。数组支持设置、查找、迭代和测试元素。
探测程序执行受到时间限制,避免了内存动态分配,且具有安全机制,如限制函数调用嵌套深度和检测潜在危险操作。
Systemtap 通过 tapset 脚本库支持共享,允许建立相互构建的脚本库,这些库可以自动解析未定义的全局符号以在脚本中进行搜索。
嵌入式 C 代码功能允许使用安全且正确的 C 代码,以补充探测功能,如遍历全局链表。此代码在内核模块中转录,并需遵守安全约束。
为了防止名称冲突,建议遵循 Systemtap tapset 开发人员的命名约定,以避免翻译或运行时错误。
Systemtap 的安装方式包括默认目录和额外目录选项,以及使用 /usr/share/systemtap/tapset/ 和 sourceware.org 等资源。
总结,Systemtap 提供了一种实用的工具,让开发者和管理员能够深入分析 Linux 系统活动,诊断性能和功能问题。尽管存在安全风险,对于内核程序员而言,它提供了访问内核信息和增强理解的有效途径。
手写webpacktapable源码,官方tapable的性能真的就一定是好的吗?
完整的手写源码仓库tapable是Webpack?插件机制核心。?mini-tapable?不仅解读官方?tapable?的源码,还用自己的思路去实现一遍,并且和官方的运行时间做了个比较,我和webpack作者相关的讨论可以点击查看。webpacktapable源码内部根据newFunction动态生成函数执行体这种优化方式不一定是好的。当我们熟悉了tapable后,就基本搞懂了webpackplugin的底层逻辑,再回头看webpack源码就轻松很多
目录src目录。这个目录下是手写所有的tapablehook的源码,每个hook都用自己的思路实现一遍,并且和官方的hook执行时间做个对比。
tapable的设计理念:单态、多态及内联缓存由于在webpack打包构建的过程中,会有上千(数量其实是取决于自身业务复杂度)个插件钩子执行,同时同类型的钩子在执行时,函数参数固定,函数体相同,因此tapable针对这些业务场景进行了相应的优化。这其中最重要的是运用了单态性及多态性概念,内联缓存的原理,也可以看这个issue。为了达到这个目标,tapable采用newFunction动态生成函数执行体的方式,主要逻辑在源码的HookCodeFactory.js文件中。
如何理解tapable的设计理念思考下面两种实现方法,哪一种执行效率高,哪一种实现方式简洁?
//方法一:constcallFn=(...tasks)=>(...args)=>{ for(constfnoftasks){ fn(...args)}}//方法二:constcallFn2=(a,b,c)=>(x,y)=>{ a(x,y);b(x,y);c(x,y);}callFn及callFn2的目的都是为了实现将一组方法以相同的参数调用,依次执行。很显然,方法一效率明显更高,并且容易扩展,能支持传入数量不固定的一组方法。但是,如果根据单态性以及内联缓存的说法,很明显方法二的执行效率更高,同时也存在一个问题,即只支持传入a,b,c三个方法,参数形态也固定,这种方式显然没有方法一灵活,那能不能同时兼顾效率以及灵活性呢?答案是可以的。我们可以借助newFunction动态生成函数体的方式。
classHookCodeFactory{ constructor(args){ this._argNames=args;this.tasks=[];}tap(task){ this.tasks.push(task);}createCall(){ letcode="";//注意思考这里是如何拼接参数已经函数执行体的constparams=this._argNames.join(",");for(leti=0;i<this.tasks.length;i++){ code+=`varcallback${ i}=this.tasks[${ i}];callback${ i}(${ params})`;}returnnewFunction(params,code);}call(...args){ constfinalCall=this.createCall();//将函数打印出来,方便观察最终拼接后的结果console.log(finalCall);returnfinalCall.apply(this,args);}}//构造函数接收的arg数组里面的参数,就是taska、b、c三个函数的参数constcallFn=newHookCodeFactory(["x","y","z"]);consta=(x,y,z)=>{ console.log("taska:",x,y,z);};constb=(x,y,z)=>{ console.log("taskb:",x,y,z);};constc=(x,y,z)=>{ console.log("taskc:",x,y,z);};callFn.tap(a);callFn.tap(b);callFn.tap(c);callFn.call(4,5,6);当我们在浏览器控制台执行上述代码时:
拼接后的完整函数执行体:
可以看到,通过这种动态生成函数执行体的方式,我们能够同时兼顾性能及灵活性。我们可以通过tap方法添加任意数量的任务,同时通过在初始化构造函数时newHookCodeFactory(['x','y',...,'n'])传入任意参数。
实际上,这正是官方tapable的HookCodeFactory.js的简化版本。这是tapable的精华所在。
tapable源码解读tapable最主要的源码在Hook.js以及HookCodeFactory.js中。Hook.js主要是提供了tap、tapAsync、tapPromise等方法,每个Hook都在构造函数内部调用consthook=newHook()初始化hook实例。HookCodeFactory.js主要是根据newFunction动态生成函数执行体。
demo以SyncHook.js为例,SyncHook钩子使用如下:
const{ SyncHook}=require("tapable");debugger;consttesthook=newSyncHook(["compilation","name"]);//注册plugin1testhook.tap("plugin1",(compilation,name)=>{ console.log("plugin1",name);compilation.sum=compilation.sum+1;});//注册plugin2testhook.tap("plugin2",(compilation,name)=>{ console.log("plugin2..",name);compilation.sum=compilation.sum+2;});//注册plugin3testhook.tap("plugin3",(compilation,name)=>{ console.log("plugin3",compilation,name);compilation.sum=compilation.sum+3;});constcompilation={ sum:0};//第一次调用testhook.call(compilation,"mytest1");//第二次调用testhook.call(compilation,"mytest2");//第三次调用testhook.call(compilation,"mytest3");...//第n次调用testhook.call(compilation,"mytestn");我们用这个demo做为用例,一步步debug。
SyncHook.js源码主要逻辑如下:
constHook=require("./Hook");constHookCodeFactory=require("./HookCodeFactory");//继承HookCodeFactoryclassSyncHookCodeFactoryextendsHookCodeFactory{ }constfactory=newSyncHookCodeFactory();constCOMPILE=function(options){ factory.setup(this,options);returnfactory.create(options);};functionSyncHook(args=[],name=undefined){ //初始化Hookconsthook=newHook(args,name);//注意这里修改了hook的constructorhook.constructor=SyncHook;...//每个钩子都必须自行实现自己的compile方法!!!hook.compile=COMPILE;returnhook;}Hook.js源码主要逻辑如下:
//问题一:思考一下为什么需要CALL_DELEGATEconstCALL_DELEGATE=function(...args){ //当第一次调用时,实际上执行的是CALL_DELEGATE方法this.call=this._createCall("sync");//当第二次或者第n次调用时,此时this.call方法已经被设置成this._createCall的返回值returnthis.call(...args);};...classHook{ constructor(args=[],name=undefined){ this._args=args;this.name=name;this.taps=[];//存储我们通过hook.tap注册的插件this.interceptors=[];this._call=CALL_DELEGATE;//初始化时,this.call被设置成CALL_DELEGATEthis.call=CALL_DELEGATE;...//问题三:this._x=undefined是什么this._x=undefined;//this._x实际上就是this.taps中每个插件的回调//问题四:为什么需要在构造函数中绑定这些函数this.compile=this.compile;this.tap=this.tap;this.tapAsync=this.tapAsync;this.tapPromise=this.tapPromise;}//每个钩子必须自行实现自己的compile方法。compile方法根据this.taps以及this._args动态生成函数执行体compile(options){ thrownewError("Abstract:shouldbeoverridden");}//生成函数执行体_createCall(type){ returnthis.compile({ taps:this.taps,interceptors:this.interceptors,args:this._args,type:type});}..._tap(type,options,fn){ ...this._insert(options);}tap(options,fn){ this._tap("sync",options,fn);}_resetCompilation(){ this.call=this._call;this.callAsync=this._callAsync;this.promise=this._promise;}_insert(item){ //问题二:为什么每次调用testhook.tap()注册插件时,都需要重置this.call等方法?this._resetCompilation();...}}思考Hook.js源码中的几个问题问题一:为什么需要CALL_DELEGATE
问题二:为什么每次调用testhook.tap()注册插件时,都需要重置this.call等方法?
问题三:this._x=undefined是什么
问题四:为什么需要在构造函数中绑定this.compile、this.tap、this.tapAsync以及this.tapPromise等方法
当我们每次调用testhook.tap方法注册插件时,流程如下:
方法往this.taps数组中添加一个插件。this.__insert方法逻辑比较简单,但这里有一个细节需要注意一下,为什么每次注册插件时,都需要调用this._resetCompilation()重置this.call等方法?我们稍后再看下这个问题。先继续debug。
当我们第一次(注意是第一次)调用testhook.call时,实际上调用的是CALL_DELEGATE方法
constCALL_DELEGATE=function(...args){ //当第一次调用时,实际上执行的是CALL_DELEGATE方法this.call=this._createCall("sync");//当第二次或者第n次调用时,此时this.call方法已经被缓存成this._createCall的返回值returnthis.call(...args);};CALL_DELEGATE调用this._createCall函数根据注册的this.taps动态生成函数执行体。并且this.call被设置成this._createCall的返回值缓存起来,如果this.taps改变了,则需要重新生成。
此时如果我们第二次调用testhook.call时,就不需要再重新动态生成一遍函数执行体。这也是tapable的优化技巧之一。这也回答了问题一:为什么需要CALL_DELEGATE。
如果我们调用了n次testhook.call,然后又调用testhook.tap注册插件,此时this.call已经不能重用了,需要再根据CALL_DELEGATE重新生成一次函数执行体,这也回答了问题二:为什么每次调用testhook.tap()注册插件时,都需要重置this.call等方法。可想而知重新生成的过程是很耗时的。因此我们在使用tapable时,最好一次性注册完所有插件,再调用call
testhook.tap("plugin1");testhook.tap("plugin2");testhook.tap("plugin3");testhook.call(compilation,"mytest1");//第一次调用call时,会调用CALL_DELEGATE动态生成函数执行体并缓存起来testhook.call(compilation,"mytest2");//不会重新生成函数执行体,使用第一次的testhook.call(compilation,"mytest3");//不会重新生成函数执行体,使用第一次的避免下面的调用方式:
testhook.tap("plugin1");testhook.call(compilation,"mytest1");//第一次调用call时,会调用CALL_DELEGATE动态生成函数执行体并缓存起来testhook.tap("plugin2");testhook.call(compilation,"mytest2");//重新调用CALL_DELEGATE生成函数执行体testhook.tap("plugin3");testhook.call(compilation,"mytest3");//重新调用CALL_DELEGATE生成函数执行体现在让我们看看第三个问题,调用this.compile方法时,实际上会调用HookCodeFacotry.js中的setup方法:
setup(instance,options){ instance._x=options.taps.map(t=>t.fn);}对于问题四,实际上这和V8引擎的HiddenClass有关,通过在构造函数中绑定这些方法,类中的属性形态固定,这样在查找这些方法时就能利用V8引擎中HiddenClass属性查找机制,提高性能。
HookCodeFactory.js主要逻辑:
classHookCodeFactory{ constructor(config){ this.config=config;this.options=undefined;this._args=undefined;}create(options){ this.init(options);letfn;switch(this.options.type){ case'sync':fn=newFunction(...)breakcase'async':fn=newFunction(...)breakcase'promise':fn=newFunction(...)break}this.deinit();returnfn;}setup(instance,options){ instance._x=options.taps.map(t=>t.fn);}...}手写tapable每个Hook手写tapable中所有的hook,并比较我们自己实现的hook和官方的执行时间
这里面每个文件都会实现一遍官方的hook,并比较执行时间,以SyncHook为例,批量注册个插件时,我们自己手写的MySyncHook执行时间0.ms,而官方的需要6ms,这中间整整倍的差距!!!
具体可以看我的仓库
原文:/post/2024-12-29 05:572953人浏览
2024-12-29 05:12326人浏览
2024-12-29 04:5966人浏览
2024-12-29 04:121011人浏览
2024-12-29 03:59603人浏览
2024-12-29 03:552339人浏览
桃勤公司搞烏龍,竟然將旅客送錯航班!昨23)天下午虎航因飛機停在外機坪上,透過接駁車載運進行登機作業,沒想到接駁車卻把飛往東京的旅客,載到飛大阪的航機上,所幸及時發現,重新清點人數,只是誤送旅客意外也
1.GNU和GPL是什么2.GPL-3.0协议版权纠纷案,明确开源许可证法律效力3.php宝塔搭建实战wordpress可视化拖拽自助建站The7_V10.0.0主题php源码4.通达信tn6公式源码