TypeSctipt类型实战

2024-11-22 13:04:35 · 0 min · Eddie Wang

JS 考题

1. 分析输出 for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 1) } for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 1) } 2. 分析输出 const shape = { radius: 10, diameter() { return this.radius * 2 }, perimeter: () => 2 * Math.PI * this.radius, } shape.diameter() shape.perimeter() 3. 分析输出 const a = {} function test1(a) { a = { name: 'wdd', } } function test2() { test1(a) } function test3() { console.log(a) } test2() test3() 4. 分析输出 class Chameleon { static colorChange(newColor) { this.newColor = newColor return this.newColor } constructor({ newColor = 'green' } = {}) { this.newColor = newColor } } const freddie = new Chameleon({ newColor: 'purple' }) freddie.colorChange('orange') 5. 分析输出 function Person(firstName, lastName) { this.firstName = firstName this.lastName = lastName } const member = new Person('Lydia', 'Hallie') Person.getFullName = function () { return `${this.firstName} ${this.lastName}` } console.log(member.getFullName()) 6. 事件传播的三个阶段是什么? A: Target > Capturing > Bubbling B: Bubbling > Target > Capturing C: Target > Bubbling > Capturing D: Capturing > Target > Bubbling 7. 所有对象都有原型 A: 对 B: 错 ...

2022-11-04 08:42:15 · 2 min · Eddie Wang

JavaScript内存泄露分析

参考: http://slides.com/gruizdevilla/memory 内存是一张图 原始类型,只能作为叶子。原始类型不能引用其他类型 数字 字符串 布尔值 除了原始类型之外,其他类型都是对象,其实就是键值对 数组是一种特殊对象,它的键是连续的数字 内存从根开始 在浏览器中,根对象是window 在nodejs中,根对象是global 任何从根无法到达的对象,都会被GC回收,例如下图的节点9和10 根节点的GC是无法控制的 路径 从根节点开始到特定对象的路径,如下图的1-2-4-6-8 支配项 每个对象有且仅有一个支配项,支配项对对象可能不是直接引用 举例子 节点1支配节点2 节点2支持节点3、4、6 节点3支配节点5 节点6支配节点7 节点5支配节点8 上面的例子有个不好理解的是节点2为什么支配了节点6?如果节点A存在于从根节点到节点B的每一个路径中,那么A就是B的支配项。2存在于1-2-4-6,也存在于1-2-3-6,所以节点2支配节点6 V8 新生代与老生代 v8内存分为新生代和老生代内存,两块内存使用不同的内存GC策略 相比而言,新生代GC很快,老生代则较慢 新生代的内存在某些条件下会被转到老生代内存区 GC发生时,用可能应用会暂停 解除引用的一些错误 var a = {name: 'wdd'} delete a.name // 这回让对象a变成慢对象 var a = {name: 'wdd'} a.name = null // 这个则更好 关于slow Object V8 optimizing compiler makes assumptions on your code to make optimizations. It transparently creates hidden classes that represent your objects. Using this hidden classes, V8 works much faster. If you “delete” properties, these assumptions are no longer valid, and the code is de-optimized, slowing your code. // Fast Object function FastPurchase(units, price) { this.units = units; this.price = price; this.total = 0; this.x = 1; } var fast = new FastPurchase(3, 25); // Slow Object function SlowPurchase(units, price) { this.units = units; this.price = price; this.total = 0; this.x = 1; } var slow = new SlowPurchase(3, 25); //x property is useless //so I delete it delete slow.x; ...

2022-10-29 11:52:59 · 2 min · Eddie Wang

JS内存泄漏分享

什么是内存泄漏? 单位时间内的内存变化量可能有三个值 正数:内存可能存在泄漏。生产环境,如果服务在启动后,该值一直是正值,从未出现负值或者趋近于0的值,那么极大的可能是存在内存泄漏的。 趋近于0的值: 内存稳定维持 负数:内存在释放 实际上,在观察内存变化量时,需要有两个前提条件 一定的负载压力:因为在开发或者功能测试环境,很少的用户,服务的压力很小,是很难观测到内存泄漏问题的。所以务必在一定的负载压力下观测。 至少要观测一天:内存上涨并不一定意味着存在内存泄漏问题。在一个工作日中,某些时间点,是用户使用的高峰期,服务的负载很高,自然内存使用会增长。关键在于在高峰期过后的低谷期时,内存是否回下降到正常值。如果内存在低谷期时依然维持着高峰期时的内存使用,那么非常大可能是存在内存泄漏了。 下图是两个服务的。从第一天的0点开始观测服务的内存,一直到第二天的12点。正常的服务会随着负载的压力增加或者减少内存使用。而存在内存泄漏的服务,内存一直在上升,并且负载压力越大,上升的越快。 有没有可能避免内存泄漏? 除非你不写代码,否者你是无法避免内存泄漏的问题的。 第一,即使你是非常精通某个语言,也是有很多关于如何避免内存泄漏的经验。但是你的代码里仍然可能会包含其他库或者其他同事写的代码,那些代码里是无法保证是否存在内存泄漏问题的。 第二,内存泄漏的代码有时候非常难以察觉。例如console.log打印的太快,占用太多的buffer。网络流量激增,占用太多的Recv_Q,node无法及时处理。写文件太慢,没有处理“后压”相关的逻辑等等。 为什么要关注内存泄漏? 为什么要关注内存泄漏?我们客户的服务器可是有500G内存的 你可能有个很豪的金主。但是你不要忘记一个故事。 传说国际象棋是由一位印度数学家发明的。国王十分感谢这位数学家,于是就请他自己说出想要得到什么奖赏。这位数学家想了一分钟后就提出请求——把1粒米放在棋盘的第1格里,2粒米放在第2格,4粒米放在第3格,8粒米放在第4格,依次类推,每个方格中的米粒数量都是之前方格中的米粒数量的2倍。 国王欣然应允,诧异于数学家竟然只想要这么一点的赏赐——但随后却大吃了一惊。当他开始叫人把米放在棋盘上时,最初几个方格中的米粒少得像几乎不存在一样。但是,往第16个方格上放米粒时,就需要拿出1公斤的大米。而到了第20格时,他的那些仆人则需要推来满满一手推车的米。国王根本无法提供足够的大米放在棋盘上的第64格上去。因为此时,棋盘上米粒的数量会达到惊人的18 446 744 073 709 551 615粒。如果我们在伦敦市中心再现这一游戏,那么第64格中的米堆将延伸至M25环城公路,其高度将超过所有建筑的高度。事实上,这一堆米粒比过去1000年来全球大米的生产总量还要多得多。 对于内存泄漏来说,可能500G都是不够用的。 实际上操作系统对进程使用内存资源是有限制的,我们关注内存泄漏,实际上是关注内存泄漏会引起的最终问题:out of memory。如果进程使用的资源数引起了操作系统的注意,很可能进程被操作系统杀死。 然后你的客户可能正在使用你的服务完成一个重要的事情,接着你们的客户投诉热线回被打爆,然后是你的老板,你的领导找你谈话~~~ 基本类型 vs 引用类型 基本类型:undefined, null, boolean, number, string。基本类型是按值访问 引用类型的值实际上是指向内存中的对象 上面的说法来自《JavaScript高级程序设计》。但是对于基本类型字符串的定义,实际上我是有些不认同的。有些人也认为字符串不属于基本类型。 就是关于字符串,我曾思考过,在JavaScript里,字符串的最大长度是多少,字符串最多能装下多少个字符? 我个人认为,一个变量有固定的大小的内存占用,才是基本类型。例如数字,null, 布尔值,这些值很容易能理解他们会占用固定的内存大小。但是字符串就不一样了。字符串的长度是不固定,在不同的浏览器中,有些字符串最大可能占用256M的内存,甚至更多。 可以参考这个问题:https://stackoverflow.com/questions/34957890/javascript-string-size-limit-256-mb-for-me-is-it-the-same-for-all-browsers 内存是一张图 1代表根节点,在NodeJS里是global对象,在浏览器中是window对象 2-6代表对象 7-8代表原始类型。分别有三种,字符串,数字,布尔值 9-10代表从根节点无法到达的对象 注意,作为原始类型的值,在内存图中只能是叶子节点。 ** 从跟节点R0无法到达的节点9,10,将会在GC时被清除。 保留路径的含义是从跟对象到某一节点的最短路径。例如1->2->4->6。 对象保留树 节点: 构造函数的名称 边缘:对象的key 距离: 节点到跟节点的最短距离 支配项(Dominators) 每个对象有且仅有一个支配项 如果B存在从根节点到A节点之间的所有路径中,那么B是A的支配项,即B支配A。 下图中 1支配2 2支配3,4,6 (想想2为什么没有支配5?) 3支配5 6支配7 5支配8 理解支配项的意义在于理解如何将资源释放。如下图所示,如果目标是释放节点6的占用资源,仅仅释放节点3或者节点4是没有用的,必需释放其支配项节点2,才能将节点6释放。 ...

2022-10-29 11:47:38 · 2 min · Eddie Wang

NodeJS Out of Memory: Backpressuring in Streams

今天我收集了一份大概有40万行的日志,为了充分利用这份日志,我决定把日志给解析,解析完了之后,再写入mysql数据库。 首先,对于40万行的日志,肯定不能一次性读取到内存。 所以我用了NodeJs内置的readline模块。 const readline = require('readline') let line_no = 0 let rl = readline.createInterface({ input: fs.createReadStream('./my.log') }) rl.on('line', function(line) { line_no++; console.log(line) }) // end rl.on('close', function(line) { console.log('Total lines : ' + line_no); }) 数据解析以及写入到这块我没有贴代码。代码的执行是正常的,但是一段时间之后,程序就报错Out Of Memory。 代码执行是在nodejs 10.16.3上运行的,谷歌搜了一下解决方案,看到有人说nodejs升级到12.x版本就可以解决这个问题。我抱着试试看的想法,升级了nodejs到最新版,果然没有再出现OOM的问题。 后来我想,我终于深刻理解了NodeJS官网上的这篇文章 Backpressuring in Streams,以前我也度过几遍,但是不太了解,这次接合实际情况。有了深刻理解。 NodeJS在按行读取本地文件时,大概可以达到每秒1000行的速度,然而数据写入到MySql,大概每秒100次插入的样子。 本身网络上存在的延迟就要比读取本地磁盘要慢,读到太多的数据无法处理,只能暂时积压到内存中,然而内存有限,最终OOM的异常就抛出了。 NodeJS 12.x应该解决了这个问题。 参考 https://nodejs.org/en/docs/guides/backpressuring-in-streams/

2022-10-29 11:46:07 · 1 min · Eddie Wang

new Date('time string')的陷阱

一般情况下,建议你不要用new Date(“time string”)的方式去做时间解析。因为不同浏览器,可能接受的time string的格式都不一样。 你最好不要去先入为主,认为浏览器会支持的你的格式。 常见的格式 2010-10-10 19:00:00 就这种格式,在IE11上是不接受的。 下面的比较,在IE11上返回false, 在chrome上返回true。原因就在于,IE11不支持这种格式。 new Date() > new Date('2010-10-10 19:00:00') 所以在时间处理上,最好选用比价靠谱的第三方库,例如dayjs, moment等等。 千万不要先入为主!!

2022-10-29 11:44:26 · 1 min · Eddie Wang

IE8/9 支持WebSocket方案,flash安全策略

IE8/9原生是不支持WebSocket的,但是我们可以使用flash去模拟一个WebSocket接口出来。 这方面,https://github.com/gimite/web-socket-js 已经可以使用。 除了客户端之外,服务端需要做个flash安全策略设置。 这里的服务端是指WebSocet服务器所在的服务端。默认端口是843端口。 客户端使用flash模拟WebSocket时,会打开一个到服务端843端口的TCP链接。 并且发送数据: <policy-file-request>. 服务端需要回应下面类似的内容 <?xml version="1.0"?> <!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <site-control permitted-cross-domain-policies="all"/> <allow-access-from domain="*" to-ports="*" secure="false"/> <allow-http-request-headers-from domain="*" headers="*"/> </cross-domain-policy> Node.js实现 policy.js module.exports.policyFile = `<?xml version="1.0"?> <!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <site-control permitted-cross-domain-policies="all"/> <allow-access-from domain="*" to-ports="*" secure="false"/> <allow-http-request-headers-from domain="*" headers="*"/> </cross-domain-policy>` index.js const Net = require('net') const {policyFile} = require('./policy') const port = 843 console.log(policyFile) const server = new Net.Server() server.listen(port, function() { console.log(`Server listening for connection requests on socket localhost:${port}`); }); server.on('connection', function(socket) { console.log('A new connection has been established.'); socket.end(policyFile) socket.on('data', function(chunk) { console.log(`Data received from client: ${chunk.toString()}`); }); socket.on('end', function() { console.log('Closing connection with the client'); }); socket.on('error', function(err) { console.log(`Error: ${err}`); }); });

2022-10-29 11:43:23 · 1 min · Eddie Wang

为什么vscode会占用大量CPU资源?

电脑的风扇声突然响了起来,我知道有某个进程在占用大量CPU资源。 在任务管理器中,可以看到vscode占用的的CPU资源达到150。说明问题出在vscode上。 在vscode中,按F1, 输入: show running extensions 可以查看所有插件的运行状况。 其中需要关注最重要的指标就是活动时间:如果某个插件的活动时间明显是其他插件的好多倍,那问题就可能出在这个插件上。要么禁用该插件,要么卸载该插件。

2022-10-29 11:42:19 · 1 min · Eddie Wang

js中二进制的操作

js原生支持16进制、10进制、8进制的直接定义 var a = 21 // 十进制 var b = 0xee // 十六进制, 238 var c = 013 // 八进制 11 十进制转二进制字符串 var a = 21 // 十进制 a.toString(2) // "10101" 二进制转10进制 var d = "10101" parseInt('10101',2) // 21

2022-10-29 11:41:13 · 1 min · Eddie Wang

NodeJS边下载边解压gz文件

const fs = require('fs') var request = require('request') const zlib = require('zlib') const log = require('./log.js') const fileType = '' let endCount = 0 module.exports = (item) => { return new Promise((resolve, reject) => { request.get(item.url) .on('error', (error) => { log.error(`下载失败${item.name}`) reject(error) }) .pipe(zlib.createGunzip()) .pipe(fs.createWriteStream(item.name + fileType)) .on('finish', (res) => { log.info(`${++endCount} 完成下载 ${item.name + fileType}`) resolve(res) }) }) }

2022-10-29 11:39:37 · 1 min · Eddie Wang