1.代码拆分-使用SplitChunks
2.å¦ä½å¨vueä¸ä½¿ç¨tsç示ä¾ä»£ç
3.js里面的源码onface是什么意思
4.nodejs EventEmitter 源码分析
代码拆分-使用SplitChunks
前言
探索代码优化的世界,最近开始接触项目优化工作,源码其中涉及三方组件的源码拆分。在未进行拆分前,源码可能存在两个场景:单一js文件过大,源码影响缓存效率;无法有效管理第三方库。源码同花顺底部放量公式源码利用`splitChunks`工具,源码可以将模块进行分割,源码并提取重复代码,源码解决上述问题。源码
概念区分 - module、源码bundle、源码chunk
深入理解`splitChunks`之前,源码先梳理几个概念。源码module:模块,源码在webpack中,任何文件都可视为模块,需要配置loader将其转换为支持打包的单页app下载页面源码文件。chunk:编译完成待输出时,webpack将module按特定规则组合成一个个chunk。bundle:webpack处理完chunk文件后,生成供浏览器运行的代码。
chunk与bundle的关系
探析chunk的构成与bundle之间的关联。chunk有两种形式:初始化(initial)chunk,即入口起点的主chunk,包含入口起点及其依赖的所有模块;非初始化(non-initial)chunk,用于延迟加载,可能在使用动态导入或`SplitChunksPlugin`时出现。
通过入口产生的chunk
假设目录结构如下:index.js, another-module.js, webpack.config.js, package.json添加script配置,运行webpack并使用ndb追踪代码执行。通过命令启动浏览器,点击播放按钮执行build命令,追踪chunk到bundle的流转。
chunk处理步骤概览
从`Compilation`类的`seal`方法出发,首先搜集chunks,通达信主力资金反转源码然后调用`createChunkAssets`方法生成source,为输出文件做准备;通过`compilation.emitAssets`方法记录资源信息到`compilation.assets`对象;一系列回调最终调用`onCompiled`方法,将assets信息写入输出目录,生成bundle文件。
Demo2 - 动态导入
将`index.js`中的lodash通过`import`方式导入,动态导入返回promise,通过`then`获取导入信息。修改`webpack.config.js`入口为单个`index.js`。源码追踪显示,初始化文件新增一个名为`index`的chunk,但在模块分析中识别到`import`方式,为`index.js`模块增加了`AsyncDependenciesBlock`标记,经过处理生成一个名为`null`的chunk。
总结:`chunk`是源代码中的抽象,封装定义如何将模块组写入文件,而`bundle`则是输出目录的文件。
解决隐患 - `splitChunks`配置
在上述示例中,有源码怎么做网站的存在三方模块重复引用的问题。通过简单的`optimization.splitChunks`配置,实现了lodash的抽离,降低了单个入口文件的大小。总结使用心得,`splitChunks`主要用于代码优化,针对不同场景配置`chunks`选项,如`all`、`async`、`initial`以及自定义函数,以达到高效拆分效果。
比较`async`、`initial`、`all`的区别
在示例中增加`another.js`,静态导入lodash,对比`async`、`all`、文件大小没变源码显示00`initial`的不同效果。默认情况下,`initial`影响HTML文件中的脚本标签,而`async`仅针对动态导入,`all`则考虑更多场景,适合存在复用模块的情况,但需权衡动态导入及其内部依赖的抽离。
splitChunks.cacheGroups
在使用`splitChunks`基础上,通过`cacheGroups`实现更细粒度的代码拆分,进一步优化项目结构。
总结
通过`splitChunks`配置,实现三方组件的高效管理与拆分,优化代码结构与加载效率。理解模块、bundle、chunk之间的关系,以及如何利用`splitChunks`与`cacheGroups`进行代码拆分与优化,是提升项目性能的关键步骤。
å¦ä½å¨vueä¸ä½¿ç¨tsç示ä¾ä»£ç
æ¬æä»ç»äºå¦ä½å¨vueä¸ä½¿ç¨tsç示ä¾ä»£ç ï¼å享ç»å¤§å®¶ï¼å ·ä½å¦ä¸ï¼
注æï¼æ¤æ并ä¸æ¯ævueæ¹ä¸ºå ¨é¨æ¿æ¢ä¸ºtsï¼èæ¯å¯ä»¥å¨åæ¥ç项ç®ä¸æ¤å ¥tsæ件ï¼ç®ååªæ¯å®è·µé¶æ®µï¼åts转åè¿ç¨ä¸çè¿æ¸¡ã
tsæä»ä¹ç¨ï¼
ç±»åæ£æ¥ãç´æ¥ç¼è¯å°åçjsãå¼å ¥æ°çè¯æ³ç³
为ä»ä¹ç¨tsï¼
TypeScriptç设计ç®çåºè¯¥æ¯è§£å³JavaScriptçâçç¹âï¼å¼±ç±»åå没æå½å空é´ï¼å¯¼è´å¾é¾æ¨¡ååï¼ä¸éåå¼å大åç¨åºãå¦å¤å®è¿æä¾äºä¸äºè¯æ³ç³æ¥å¸®å©å¤§å®¶æ´æ¹ä¾¿å°å®è·µé¢å对象çç¼ç¨ã
typescriptä¸ä» å¯ä»¥çº¦ææ们çç¼ç ä¹ æ¯ï¼è¿è½èµ·å°æ³¨éçä½ç¨ï¼å½æ们çå°ä¸å½æ°åæ们ç«é©¬å°±è½ç¥éè¿ä¸ªå½æ°çç¨æ³ï¼éè¦ä¼ ä»ä¹å¼ï¼è¿åå¼æ¯ä»ä¹ç±»åä¸ç®äºç¶ï¼å¯¹å¤§å项ç®çç»´æ¤æ§æå¾å¤§çæåãä¹ä¸è³äºä½¿å¼åè æ¬èµ·ç³å¤´ç ¸èªå·±çèã
Angular: æ们为ä»ä¹éæ©TypeScript?
TypeScript éä¼ç§çå·¥å ·
TypeScript æ¯ JavaScript çè¶ é
TypeScript 使å¾æ½è±¡æ¸ æ°å¯è§
TypeScript 使代ç æ´å®¹æé 读åç解
æ¯çï¼æç¥éè¿çèµ·æ¥å¹¶ä¸ç´è§ã让æç¨ä¸ä¸ªä¾åæ¥è¯´ææçææã让æ们æ¥ççè¿ä¸ªå½æ°jQuery.ajax()ãæ们è½ä»å®çç¾åä¸å¾å°ä»ä¹ä¿¡æ¯?
æ们å¯ä¸è½ç¡®å®çæ¯è¿ä¸ªå½æ°æ两个åæ°ãæ们å¯ä»¥çæµè¿äºç±»åãä¹è®¸ç¬¬ä¸ä¸ªæ¯å符串ï¼ç¬¬äºä¸ªæ¯é 置对象ãä½è¿åªæ¯çæµï¼æ们å¯è½éäºãæ们ä¸ç¥éä»ä¹é项è¿å ¥è®¾ç½®å¯¹è±¡(å®ä»¬çå称åç±»å)ï¼æè 该å½æ°è¿åä»ä¹ã
å¨ä¸æ£æ¥æºä»£ç æææ¡£çæ åµä¸ï¼æ们ä¸å¯è½è°ç¨è¿ä¸ªå½æ°ãæ£æ¥æºä»£ç 并ä¸æ¯ä¸ä¸ªå¥½çéæ©ââæ¥æå½æ°åç±»çç®çï¼æ¯å¨ä¸ç¥éå¦ä½å®ç°å®ä»¬çæ åµä¸ä½¿ç¨å®ä»¬ãæ¢å¥è¯è¯´ï¼æ们åºè¯¥ä¾èµäºä»ä»¬çæ¥å£ï¼èä¸æ¯ä»ä»¬çå®ç°ãæ们å¯ä»¥æ£æ¥ææ¡£ï¼ä½è¿å¹¶ä¸æ¯æ好çå¼åç»éªââå®éè¦é¢å¤çæ¶é´ï¼èä¸ææ¡£ç»å¸¸è¿æã
å æ¤ï¼å°½ç®¡å¾å®¹æé 读jQuery.ajax(url,settings)ï¼çæ£ç解å¦ä½è°ç¨è¿ä¸ªå½æ°ï¼æ们éè¦é 读å®çå®ç°æå®çææ¡£ã
以ä¸æ¯ä¸ä¸ªç±»åçæ¬ï¼
å®ç»äºæ们æ´å¤çä¿¡æ¯ã
è¿ä¸ªå½æ°ç第ä¸ä¸ªåæ°æ¯ä¸ä¸ªå符串ã
设置åæ°æ¯å¯éçãæ们å¯ä»¥çå°ææå¯ä»¥ä¼ éå°å½æ°ä¸çé项ï¼ä¸ä» æ¯å®ä»¬çå称ï¼è¿å æ¬å®ä»¬çç±»åã
å½æ°è¿åä¸ä¸ªJQueryXHR对象ï¼æ们å¯ä»¥çå°å®çå±æ§åå½æ°ã
ç±»ååç¾åè¯å®æ¯æªç±»ååçç¾åé¿ï¼ä½æ¯:stringï¼:JQueryAjaxSettingsåJQueryXHR并ä¸æ¯æ··ä¹±çã å®ä»¬æ¯æé«ä»£ç çå¯ç解æ§çéè¦ææ¡£ãæ们å¯ä»¥æ´æ·±å ¥å°ç解代ç ï¼èä¸å¿ æ·±å ¥å°å®ç°æ读åææ¡£ä¸ã æç个人ç»éªæ¯ï¼æå¯ä»¥æ´å¿«å°é 读类åå代ç ï¼å 为类åæä¾äºæ´å¤çä¸ä¸ææ¥ç解代ç ã
æèª Angular: æ们为ä»ä¹éæ©TypeScript?
ts好å¦åï¼
TypeScriptçä¸ä¸ªè®¾è®¡äº®ç¹å°±æ¯å®å¹¶æ²¡ææå¼JavaScriptçè¯æ³å¦èµ·çç¶ï¼èæ¯åæäºJavaScriptçè¶ éï¼è¿ä¸ªåå³åºè¯¥è®°å¨Andersä¸ï¼ï¼è¿æ ·ä»»ä½åæ³çJavaScriptçè¯å¥å¨TypeScriptä¸é½æ¯åæ³çï¼ä¹å°±æ¯è¯´å¦ä¹ ææ¬å¾ä½ï¼å¦æä½ å¯¹JavaScriptææ¯è¾æ·±å ¥çäºè§£ï¼é£ä¹å ¶å®å¯ä»¥å¾å¿«çä¸æTypeScriptï¼å 为å®ç设计é½æ¯é对JavaScriptç使ç¨ä¹ æ¯åæ¯ä¾ã
ä¸äºç®åçä¾åï¼ä¸çå³æï¼
åºç¡ç±»å
let isDone: boolean = false; // å¸å°å¼
let decLiteral: number = 6; // æ°å
let name: string = "bob"; // å符串
let list: number[] = [1, 2, 3]; // æ°ç»
...
...
æ¥å£
function printLabel(labelledObj: { label: string }) { console.log(labelledObj.label);
} let myObj = { size: , label: "Size Object" };
printLabel(myObj);
ç±»åæ£æ¥å¨ä¼æ¥çprintLabelçè°ç¨ã printLabelæä¸ä¸ªåæ°ï¼å¹¶è¦æ±è¿ä¸ªå¯¹è±¡åæ°æä¸ä¸ªå为labelç±»å为stringçå±æ§ã éè¦æ³¨æçæ¯ï¼æä»¬ä¼ å ¥ç对象åæ°å®é ä¸ä¼å å«å¾å¤å±æ§ï¼ä½æ¯ç¼è¯å¨åªä¼æ£æ¥é£äºå¿ éçå±æ§æ¯å¦åå¨ï¼å¹¶ä¸å ¶ç±»åæ¯å¦å¹é ã
å½ç¶è¿æä¸äºé«çº§çç¨æ³ï¼è¿éå°±ä¸åè¿å¤çä»ç»äºï¼äºè§£æ´å¤
å¦ä½å¨vue项ç®ä¸åºç¨tsï¼
1ãé¦å å®è£ ts
npm install --save-dev typescript npm install --save-dev ts-loader
2ãå¨æ ¹ç®å½å»ºtsconfig.jsonæ件
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"lib": ["dom","es"],
"target": "es5"
},
"include": ["./src/**/*"] }
3ãå¨é ç½®ä¸æ·»å ts-loader
{
test: /\.tsx?$/,
loader: 'ts-loader', exclude: /node_modules/, options: {
appendTsSuffixTo: [/\.vue$/],
}
}
4ãæåæ .ts åç¼æ·»å ä¸å°±OKäºï¼å¨webpack.base.conf.jsæ件ä¸
ç°å¨å°±å¯ä»¥å¨æ们åæ¬ç项ç®ä¸ä½¿ç¨tsæ件äºã
å¦ä½å®è·µï¼
1ãå¦ä½å¨jsä¸å¼ç¨tsæ件ï¼
ç±äºjsæ件没æç±»åæ£æµï¼å½æ们ætsæ件å¼å ¥çæ¶åï¼tsæ件ä¼è½¬åæjsæ件ï¼æ以å¨jsæ件ä¸å¼ç¨tsæ件çæ¹æ³ç±»åæ£æµæºå¶ä¸ä¼çæãä¹å°±æ¯è¯´åªæå¨tsæ件å æä¼æç±»åæ£æµæºå¶ã
é£ä¹æä¹å¨jsæ件ä¸ä½¿ç¨ç±»åæ£æµæºå¶å¢ï¼å°ç¼èªå·±å°è£ äºä¸å¥typeCheckçdecoratoræ¹æ³ï¼ä» ä¾åèï¼ç¨æ³å¦ä¸ï¼
@typeCheck('object','number') deleteItem(item,index) { }
æ£æµdeleteItemæ¹æ³åæ°ï¼ item为objectç±»åï¼index为numberç±»åï¼å¦æç±»åä¸å¹é å°ä¼æåºå¼å¸¸
é¨å代ç ç®ä¸ï¼
const _check = function (checked,checker) {
check: for(let i = 0; i < checked.length; i++) { if(/(any)/ig.test(checker[i])) continue check; if(_isPlainObject(checked[i]) && /(object)/ig.test(checker[i])) continue check; if(_isRegExp(checked[i]) && /(regexp)/ig.test(checker[i])) continue check; if(Array.isArray(checked[i]) && /(array)/ig.test(checker[i])) continue check; let type = typeof checked[i]; let checkReg = new RegExp(type,'ig') if(!checkReg.test(checker[i])) { console.error(checked[i] + 'is not a ' + checker[i]); return false;
}
} return true;
} /
*** @description æ£æµç±»å
* 1.ç¨äºæ ¡æ£å½æ°åæ°çç±»åï¼å¦æç±»åé误ï¼ä¼æå°é误并ä¸åæ§è¡è¯¥å½æ°ï¼
* 2.ç±»åæ£æµå¿½ç¥å¤§å°åï¼å¦stringåStringé½å¯ä»¥è¯å«ä¸ºå符串类åï¼
* 3.å¢å anyç±»åï¼è¡¨ç¤ºä»»ä½ç±»ååå¯æ£æµéè¿ï¼
* 4.å¯æ£æµå¤ä¸ªç±»åï¼å¦ "number array",两è åå¯æ£æµéè¿ãæ£åæ£æµå¿½ç¥è¿æ¥ç¬¦ ï¼
*/
export function typeCheck() { const checker = Array.prototype.slice.apply(arguments); return function (target, funcName, descriptor) { let oriFunc = descriptor.value;
descriptor.value = function () { let checked = Array.prototype.slice.apply(arguments); let result = undefined; if(_check(checked,checker) ){
result = oriFunc.call(this,...arguments);
} return result;
}
}
};
tsçç±»åæ£æµé åtypeCheckåºæ¬ä¸å·²ç»æ»¡è¶³äºæ们çéè¦ã
2ãå¦ä½å¨tsä¸å¼ç¨jsæ件ï¼
ç±äºjsæ件ä¸æ²¡æç±»åæ£æµï¼æ以tsæ件å¼å ¥jsæ件æ¶ä¼è½¬å为anyç±»åï¼å½ç¶æ们ä¹å¯ä»¥å¨ .d.tsæ件ä¸å£°æç±»åã
å¦ global.d.ts æ件
å½ç¶æçæ¶åæ们éè¦ä½¿ç¨ä¸äºåºï¼ç¶è并没æ声ææ件ï¼é£ä¹æ们å¨tsæ件ä¸å¼ç¨çæ¶åå°±ä¼æ¯undefinedãè¿ä¸ªæ¶åæ们åºè¯¥æä¹åï¼
æ¯å¦ææ³è¦å¨util.tsæ件ä¸ç¨ âquery-string'çæ¶åæ们就ä¼è¿æ ·å¼ç¨ï¼
import querystring from 'query-string';
ç¶èå½ä½ æå°querystring çæ¶åæ¯undefinedãå¦ä½è§£å³å¢ï¼å°ç¼çæ¹æ³ä¹ä» ä¾åè
æ°å»ºmodule.jsæ件
import querystring from 'query-string'; export const qs = querystring;
utile.ts æ件
import { qs } from './module.js';
解å³äºãæå°qsä¸åæ¯undefinedï¼å¯ä»¥æ£å¸¸ä½¿ç¨qsåºäºå¦ã
è³æ¤æ¬æå°±å°tså¨vueä¸çé ç½®ä»ç»ç»æï¼æ¤æåªä»£è¡¨ä¸ªäººçæ³ï¼èèå°é¡¹ç®çæ©å±æ§ï¼æ以没æå ¨é¨æ¿æ¢ætsï¼åªæ¯å°è¯æ§å¨vueä¸å¼å ¥tsï¼è¿æå¾å¤éè¦æ¹è¿çå°æ¹ï¼å¦æææ´å¥½ç建议åæè§å¯ä»¥èç³»æï¼
js里面的onface是什么意思
AngularJs和Jquery的有什么不同?
Jquery的主要目的是简化Js编写,专注于浏览器跨平台,主要用来操作DOM.
AngularJs主要关注Html数据的获取和呈现,以及应对日益复杂的Web应用需求,使得开发庞大的Web应用能够更加容易。
AngularJs呈现页面的原理
AnguarJs提供了一些对于Html进行加强的语义标签(directive),这些标签在浏览器加载完页面后被执行。举例来说:
<table id=”leaderBoard”>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="user in users">
<td>{ { user.Id}}</td>
<td>{ { user.Name}}</td>
<td>{ { user.Salary}}</td>
</tr>
</tbody>
</table>
上面的ng-repeat,就是一个directive, 相当于一个for循环。在页面加载完成后,AngularJs会遍历users数据对象,来呈现(render)出这个table中的内容。
如何实现在render完成之后,执行Js脚本
当我们使用Jquery结合AngulraJs使用的时候,希望在render完table后,执行一段js脚本,把JqTable应用到该table上。在实际开发中,会经常碰到这样的需求,希望能够捕获到AngularJs渲染完成页面的事件。
要达到这个目的,我们需要为当前的app自定义directive:
app.directive('onFini www.hnnedu.com shRenderFilters', function ($timeout) {
return {
restrict: 'A',
link: function(scope, element, attr) {
if (scope.$last === true) {
$timeout(function() {
scope.$emit('ngRepeatFinished');
});
}
}
};
});
然后,在我们需要监控的地方,加上该directive:
<tr ng-repeat="user in users" on-finish-render-filters>
<td>{ { user.Id}}</td>
<td>{ { user.Name}}</td>
<td>{ { user.Salary}}</td>
</tr>
最后,补充上我们需要render完成之后的Js脚本:
$scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) {
//下面是在table render完成后执行的js
var table = $("#leaderBoard").dataTable({
bJQueryUI: true,
"sScrollX": '%',
});
});
nodejs EventEmitter 源码分析
EventEmitter 是 Node.js 中的事件管理器核心逻辑简单,主要聚焦于事件与函数或函数数组之间的关联。在 v..1 版本中,核心逻辑在实例的 _events 属性上展开,该属性是一个对象,其键为事件名称,值为事件对应的函数或函数数组。所有方法均围绕 _events 展开。
构造函数初始化 _events 属性,若实例本身未定义,则执行此操作。此操作涉及对实例原型的引用,通过 ObjectGetPrototypeOf 的使用来实现。函数 on 允许用户注册事件监听器,逻辑简单明了:判断同名事件是否已注册,无则注册;已有则将新监听器加入已有函数数组中。emit 方法触发事件,根据事件名称获取对应函数或函数数组,使用 ReflectApply 调用。此方法与 Function.prototype.apply 类似,但提供了更简洁的实现。
off 方法与 on 方法相似,但逻辑相反。它获取事件监听器,若为函数,则直接删除;若为数组,则遍历删除指定监听器。此方法同样简洁,直接操作事件列表。
Reflect API 的使用在不同版本的 EventEmitter 中逐渐增多,例如将 Object.keys 替换为 Reflect.ownKeys,以更好地处理 Symbol 类型的事件名。反射方法,如 Reflect.apply,尽管在 V8 中源码显得复杂,但其执行逻辑与 Function.prototype.apply 相似,性能上并无显著提升,但提升了代码的可读性。
在最新版本 v.5.0 中,EventEmitter 的实现中采用 Reflect.ownKeys 更为合理,因为此方法能有效避免返回数组中无 Symbol 的问题。EventEmitter 的构造函数与 Stream 的关系展示了如何利用继承来扩展功能。Stream 通过继承 EventEmitter,实现了更简洁的 class 写法,未来可能进一步简化。
此外,文章还讨论了私有属性的使用,以及简易版 EventEmitter 的实现。简易版 EventEmitter 基本逻辑简洁,但不包含参数校验、异常处理和性能优化等生产环境所需的功能。实际生产环境中的 EventEmitter 实现则需额外处理这些复杂情况。