You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
"use strict";// 基类constHook=require("./Hook");constHookCodeFactory=require("./HookCodeFactory");classSyncHookCodeFactoryextendsHookCodeFactory{content({ onError, onResult, onDone, rethrowIfPossible }){returnthis.callTapsSeries({onError: (i,err)=>onError(err),
onDone,
rethrowIfPossible
});}}constfactory=newSyncHookCodeFactory();classSyncHookextendsHook{// 未提供的方法直接抛出异常提示tapAsync(){thrownewError("tapAsync is not supported on a SyncHook");}tapPromise(){thrownewError("tapPromise is not supported on a SyncHook");}// 为调用方法call、callAsync、promise提供依赖compile(options){factory.setup(this,options);returnfactory.create(options);}}module.exports=SyncHook;
正如上面的代码所以,直观来看就是集成了两个基类,然后导出钩子函数,先从Hook说起:
"use strict";constutil=require("util");// 抛出警告constdeprecateContext=util.deprecate(()=>{},"Hook.context is deprecated and will be removed");classHook{constructor(args=[]){// 参数们this._args=args;// 类似监听模式下的队列this.taps=[];// 拦截器this.interceptors=[];// 初始化相关调用方法this.call=this._call;this.promise=this._promise;this.callAsync=this._callAsync;// 自定义的方法队列this._x=undefined;}compile(options){// 必须重写compile方法thrownewError("Abstract: should be overriden");}// 用于创建相关调用方法的私有方法_createCall(type){// 被重写的compile方法returnthis.compile({taps: this.taps,interceptors: this.interceptors,args: this._args,type: type});}_tap(type,options,fn){// 参数处理if(typeofoptions==="string"){options={name: options};}elseif(typeofoptions!=="object"||options===null){thrownewError("Invalid tap options");}if(typeofoptions.name!=="string"||options.name===""){thrownewError("Missing name for tap");}if(typeofoptions.context!=="undefined"){deprecateContext();}options=Object.assign({ type, fn },options);// 拦截器options=this._runRegisterInterceptors(options);this._insert(options);}tap(options,fn){this._tap("sync",options,fn);}tapAsync(options,fn){this._tap("async",options,fn);}tapPromise(options,fn){this._tap("promise",options,fn);}// 拦截器_runRegisterInterceptors(options){for(constinterceptorofthis.interceptors){if(interceptor.register){constnewOptions=interceptor.register(options);if(newOptions!==undefined){options=newOptions;}}}returnoptions;}withOptions(options){constmergeOptions=opt=>Object.assign({},options,typeofopt==="string" ? {name: opt} : opt);// Prevent creating endless prototype chainsoptions=Object.assign({},options,this._withOptions);constbase=this._withOptionsBase||this;constnewHook=Object.create(base);newHook.tap=(opt,fn)=>base.tap(mergeOptions(opt),fn);newHook.tapAsync=(opt,fn)=>base.tapAsync(mergeOptions(opt),fn);newHook.tapPromise=(opt,fn)=>base.tapPromise(mergeOptions(opt),fn);newHook._withOptions=options;newHook._withOptionsBase=base;returnnewHook;}isUsed(){returnthis.taps.length>0||this.interceptors.length>0;}intercept(interceptor){this._resetCompilation();this.interceptors.push(Object.assign({},interceptor));if(interceptor.register){for(leti=0;i<this.taps.length;i++){this.taps[i]=interceptor.register(this.taps[i]);}}}_resetCompilation(){this.call=this._call;this.callAsync=this._callAsync;this.promise=this._promise;}_insert(item){this._resetCompilation();letbefore;if(typeofitem.before==="string"){before=newSet([item.before]);}elseif(Array.isArray(item.before)){before=newSet(item.before);}letstage=0;if(typeofitem.stage==="number"){stage=item.stage;}leti=this.taps.length;while(i>0){i--;constx=this.taps[i];this.taps[i+1]=x;constxStage=x.stage||0;if(before){if(before.has(x.name)){before.delete(x.name);continue;}if(before.size>0){continue;}}if(xStage>stage){continue;}i++;break;}this.taps[i]=item;}}functioncreateCompileDelegate(name,type){returnfunctionlazyCompileHook(...args){this[name]=this._createCall(type);returnthis[name](...args);};}Object.defineProperties(Hook.prototype,{_call: {value: createCompileDelegate("call","sync"),configurable: true,writable: true},_callAsync: {value: createCompileDelegate("callAsync","async"),configurable: true,writable: true},_promise: {value: createCompileDelegate("promise","promise"),configurable: true,writable: true}});module.exports=Hook;
由于webpack底层使用Tapable创建和执行钩子,所以也大致了解下tapable的原理
Tapable使用es6语法翻新了一遍,目前都是基于类的方式编写的。我们先看下目录结构:
我们其实主要看Hook.js和HookCodeFactory.js就够了,其他的基本都是大同小异的,都是依赖于这两个基类,然后扩展Hook的compile方法和HookCodeFactory的content方法,下面直接上代码。
因为几乎是大同小异,所以我们这里以最简单的SyncHook为实例:
正如上面的代码所以,直观来看就是集成了两个基类,然后导出钩子函数,先从Hook说起:
我们需要用tap、tapAsync、tapPromise往队列中添加函数,然后使用call来调用,不过call会根据不同类型的钩子产出不同的函数,这也是tapable做的优化,而这些函数的产出这来自HookCodeFactory:
核心内容都在这里,剩下的方法基本都大同小异,具体的代码细节并没有仔细去看,毕竟是别人写的,就好像你通过答案接触题目一样,感觉时间成本太高,所以仅仅是简单了解一下。
有一点很重要,比如SyncHook和SyncLoopHook这两种方法,他们的区别仅仅就是产出的函数内容不一样,前者是直接获取钩子函数然后调用,后者是一个do-while循环调用钩子函数,可想而知剩余的方法的区别也是方法内体,也就是说你需要更多的关注content方法的onResult这个参数
The text was updated successfully, but these errors were encountered: