-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.json
1 lines (1 loc) · 25.5 KB
/
search.json
1
[{"title":"TypeScript初学笔记","date":"2020-01-25T16:23:05.000Z","url":"/blog/2020/01/25/yuque/TypeScript初学笔记/","content":"初言新年快乐。现在疫情还是比较严重,于是在家看了一天的视频,学了个内容短又实用的ts,基本的概念自己都写在xmind上了:ts就是js的超集,引入了一些java,c#的概念,而且有es6+中class、decorator的概念,更完善了js语言类型和约束,使得代码更好维护,虽然前期写得很困难,但是我觉得还是挺香的。接下来如果有实践的项目的话可能会补充实践笔记吧~新年快乐!"},{"title":"TC39新提案——WeakReferences(弱引用)","date":"2020-01-03T09:49:21.000Z","url":"/blog/2020/01/03/yuque/TC39新提案——WeakReferences(弱引用)/","content":"目前提案进度:stage 3。Motivation弱引用的主要用途是实现保存大型对象的缓存或映射,在这种情况下,不希望仅因为大型对象出现在缓存或映射中而使其保持活动状态。一般来说,JavaScript中对象的引用都是强引用,只要保留着对象的引用,它就不会被垃圾回收;在ES6标准中,出现了WeakMap、WeakSet的数据结构,可以将对象弱引用,以WeakMap为例,它的特点是这样的:只接受对象作为键名(null除外);键名所引用的对象都是弱引用,垃圾回收机制不会考虑WeakMap中的引用;但是WeakMap不是真正意义上的弱引用:只要键存在,他就能强制引用;也就是对键名的弱引用;下面是提案中的示例:例如,如果您有许多大的二进制图像对象(例如ArrayBuffers),则可能希望将名称与每个图像相关联。现有的数据结构只是不执行此处所需的操作:如果使用map结构将名称映射到图像,或将图像映射到名称,则图像对象将保持活动状态,因为它们在映射中显示为值或键。WeakMap也不适用于此目的:它们的弱引用作用于key上,但是在这种情况下,我们需要一个结构,是对值的弱引用。UsageWeakRefWeakRef 是一个更高级的 API,它提供了真正的弱引用,并在对象的生命周期中插入了一个窗口。针对上面的示例,我们可以使用weakRef对象来进行对图像数据的缓存;以上代码仍然会有一个问题:weakRef对象虽然会在GC阶段回收,map中指向weakRef的键值却会不断生成,没有被回收,那么在遍历map的时候速度就会变慢,这时候可以用finalizer(终结器)来帮助清除键值。FinalizersFinalizer是对象被回收之后的回调执行器。Finalizers比较tricky,最好避免使用它;比如说,finalizer在关闭浏览器或者进程退出的时候不会被调用;它们对于GC来说不能起到帮助的作用,相反还会干扰GC的计数:GC在经过一定数量分配后,会决定有必要时的堆扫描,而注册finalizer对象总是代表着GC看不见的分配量,这会造成实际上资源使用量会高于GC计算的使用量。()在此,我们注册一个回调,以便在图像对象被垃圾回收时从缓存中删除键:不要在终结器的代码块中放置重要的逻辑。因为,无法预测什么时候,甚至不确定是否会调用给定的终结器。最好将 WeakRef 和终结器视为渐进式增强:如果自定义终结器代码运行了,那最好;但是,在它没有运行的情况下,程序应该仍然可以正常运行。WeakRef 和终结器可以帮助我们节省内存,并且在被当一种作渐进式增强的手段少量使用时,效果最佳。由于它们是高级用户特性,我们期望尽量只在框架或库中使用它们。总结WeakRef结构比WeakMap带来更高级的使用,它是真正意义上的弱引用,它可以在保存大数据的时候提供即使有引用也会被资源回收的功能,防止了内存溢出和提供更优秀的性能;Finalizer是对象被GC之后的回调,但是它不稳定且会阻碍GC的正常机制,但是它可以定位到内部内存泄漏,和清除引用weakRef的key值等等。"},{"title":"写给自己看的git笔记","date":"2019-12-17T03:13:46.000Z","url":"/blog/2019/12/17/yuque/写给自己看的git笔记/","content":"区域分配Workspace:工作区Index / Stage:暂存区Repository:仓库区(或本地仓库)Remote:远程仓库常用命令基本快照命令git addgit statusgit diff git reset git commitgit rmgit mv (git rm / git mv 与普通Linux命令不同的是,执行之后会自动add到stage区)分支&解决冲突git branchgit checkoutgit mergegit mergetoolgit stash git stash apply / drop 取栈顶 / 丢栈顶git tag远程FETCH_HEAD: 远程的最新一次commit;git fetchgit pull ( === git fetch && git merge FETCH_HEAD)git push git remote补丁git apply用法:生成补丁: git diff > myPatch.patch应用补丁: git:(feature-branch) git apply myPatch.patch根据 patch 文件内的信息,在现有文件中添加或删除内容。(修改内容仍放在工作区)应用场景:在比较敏感、无共享内网的工作环境下,本地修改生成补丁之后用u盘传给别人(true story)git cherry-pick:可以选择某一个分支中的一个或几个commit(s)来进行操作用法:git cherry-pick <commit_id>git cherry-pick .. (批量区间commit)注意:当执行完 cherry-pick 以后,将会生成一个新的提交;这个新的提交的哈希值和原来的不同,但标识名一样;git revert : 与reset相似,撤销某次commit的内容,但是是反向commit而不是回退版本,将会向前commit;批量撤销用法:git rebase :中文解释为变基,就是修改分支上的基线,把分叉的提交历史“整理”成一条直线,看上去更直观。最大的优点就是整理好commit信息,使得更加整洁,缺点就是跟踪性不好;Debuggit bisect :使用二分法来定位哪次commit出现了问题,适用于多个文件;git blame : 查看某文件每行的commit 快照,适用于单文件;管理git reflog:查看历史操作记录,对于撤销操作很有用处;git clean:清除所有untracked文件,不经常用;git gc : 清除不必要的文件和压缩优化仓库信息,用次来节约内存,不经常用;git fsck: 验证数据库中对象的连通性和有效性,可以用来找回丢失的commit、恢复被删除的数据;常见知识点git merge & git rebase 区别、各自优缺点git merge优点简单而又熟悉保留完整的历史和时间顺序维持分支的上下文缺点提交历史记录可能会被许多合并提交污染使用 git bisect 进行调试会变得更难git rebaseRebase 是将更改从一个分支集成到另一个分支的另一种方法。 Rebase 将所有更改压缩为单个“补丁”。然后它将补丁集成到目标分支上。与 merge 不同,重定位使历史变得扁平,因为它将完成的工作从一个分支转移到另一个分支。在这个过程中,不需要的历史记录被消除。优点简化可能复杂的历史记录操作单个提交很容易(例如还原它们)避免分支频繁合并提交,频繁回购。通过将它们作为单个提交来清理中间提交,这对DevOps团队很有帮助缺点将该功能分解为少量提交可以隐藏上下文在团队合作时,重新定位公共存储库可能会很危险可能带来更多的工作:使用rebase 来保持您的 feature 分支始终更新使用远程分支 Rebase 需要强制推送。人们面临的最大问题是他们强制推送,但还没有设置 git push 默认值。这会导致对本地和远程上具有相同名称的所有分支进行更新,这是非常可怕的,并且处理起来非常糟糕。"},{"title":"vue-cli3编译时构建优化实践","date":"2019-12-07T14:20:27.000Z","url":"/blog/2019/12/07/yuque/vue-cli3编译时构建优化实践/","content":"最近研究并借鉴了一下网上对webpack优化的一些措施,也对自己所负责的项目进行了优化。项目背景:单页spa应用,大多数运行在electron端上,大概有150+页面,曾经从vue-cli2移植到vue-cli3,代码体积parsed为5.4M左右,编译通常耗时4m~5m;衡量编译性能的工具spped-measure-wepack-plugin:计算每个loader和plugin编译耗时;vue GUI界面可以更直观的分析打包后每个bundle包含的modules及其大小(内置analyzer),以及其他运行命令和依赖分析等(这里重点强调analyzer,对分析打包体积更有帮助);通常cli工具已经默认搭好了一系列配置,若想探究具体配置是如何,用vue inspect / npx vue-cli-service inspect 命令就可以查看具体配置了;优化的方向编译耗时总得来说,编译增加的耗时主要在npm install 阶段、build中对chunk-vendor打包阶段(体积过大原因)、还有比较突出的babel-loader阶段。如果涉及到业务代码体积页面庞大,也需要多加重视;编译体积大体的方向就是查看analyzer每个bundle的具体情况,有多余的vendor就考虑剔除,以及压缩代码,按需引用等,对于业务代码,则考虑分包+preload的形式,尽量不要阻塞页面加载;#具体措施npm install阶段若是在gitlab ci则考虑用cache字段进行缓存(此部分没有进行细究),针对公司发布环境则进行了一套优化流程:检查依赖包是否有更新 + npm ci + npm i结合的形式,以此来省略npm i流程,具体流程如图:npm-ci和npm install不同之处有:该项目必须依赖package-lock.json如果程序包锁中的依赖项与package.json中的依赖项不匹配,则npm ci将退出并显示错误,而不是更新程序包锁。 npm ci一次只能安装整个项目:此命令不能添加单个依赖项。 如果已经存在一个node_modules,它将在npm ci开始安装之前被自动删除。 它永远不会写入package.json或任何包锁:安装实际上是冻结的。npm install,通常是用来安装依赖项:它将会安装 Node.js 项目所有的依赖项;如果使用 ^ 或 ~ 来匹配依赖项的版本时,则 npm 可能无法安装确切版本;利用 npm install 安装新依赖项时,会更新 package-lock.json。使用 npm ci,会发生:将会删除项目中的 node_modules 文件夹;会依照项目中的 package.json 来安装确切版本的依赖项;不像 npm install,npm ci 不会修改你的 package-lock.json。但是它确实期望你的项目中有一个 package-lock.json 文件 - 如果你没有这个文件,npm ci 将不起作用,此时必须使用 npm install。###build阶段webpack4 相对webpack3构建速度已经提升了很大一部分,如果这次我们要继续优化性能,则需要从其他方面入手;打包体积优化针对代码体积,主要优化了以下几点:1、分析chunk-vendors包,发现几个可以优化的依赖库对部分按需引用(如element-ui等)采用按需引入的方式而非全部引用(需要babel配置);jQuery原本已是cdn全局引入方式,还重复安装了npm依赖,因此采用external字段将jQuery剔除到bundle中;(在这里碰到了一个坑,jq采用cdn引用后electron上运行不了,这是由于Electron 的 Renderer 端因为注入了 Node 环境,存在全局函数 require,导致 jQuery 内部环境判断有问题,所以只能把jq改回npm引入方式,如果想使用cdn方式而且不需要在网页里面使用 node 模块(包括 electron 模块),建议把 BrowserWindow 的webPreferences.nodeIntegration 设置为 false。)2、使用uglifyJSplugin/terser-webpack-plugin压缩代码;3、删除线上sourcemap:是的,项目在线上仍在使用sourcemap,不单只是对体积有影响,对源码泄漏也有很大的影响,这里我把sourcemap上传到sentry之后,使用delete-sourcemap-webpack-plugin将sourcemap文件删除,这样既达到sentry跟踪源码,又防止源码泄露的效果。编译时长优化针对编译时长:1、使用happyPack配置多进程loader编译,但是原作者声明已不再维护,vue-loader也不支持happypack,本人无论如何配置找issue都无法得到解决;webpack4官方出了一个thread-loader(开销也较大), vue-cli3中还出了 选项,默认在cpu有多于一个内核时启动babel使用thread-loader,因此优化效果并不明显,故废弃;2、对于耗时较长的loader,可使用include/include来抽离需要转义的文件路径,如exclude掉node_modules,节省转义时间;(待实践);3、webpack DllPlugin和DllReferencePlugin配置此措施为优化作用最明显的方法,dll为动态链接库,在webpack中可理解为对基础依赖的映射。通常第三方库不怎么更新,dllplugin作用就是将这些库抽离出来打包到单独的动态链接库中,当导入的模块存在于这个链接库中,则不会再次打包,而是从动态库中获取,从而节省这些库的编译时间,也相当于预编译;首先我们先创建webpack.dll.conf.js,为创建dll的配置:然后我们npm run dll更新动态库内容,此时生成vendor-manifest.json ,vendor.dll.js,两个文件,前者为映射文件,后者为执行文件,需要手动放入index.html中,这里使用了AddAssetHtmlPlugin直接注入;最后需要在vue.config.js配置DllReferencePlugin,来声明动态链接库的引用;并非所有非业务相关库都建议使用dllplugin假设我们使用的element-ui已经如上方所说是按需引入,我们如果在dll配置声明了element-ui ,那么dll就会将这个库全部打包,而正式打包的时候也会将element按需引入,造成体积浪费;如果dll中某个库要升级,那么也要手动更新dll,增加维护成本,如果没注意,就会引用到旧的库;所以建议只在稳定的库中引用dllplugin,以及不依赖process.env环境的库使用plugin;4、noParse选项防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中不应该含有 import, require, define 的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。vue-cli已配置了vue全家桶的文件,后期可考虑优化lodash等第三方独立的库。#优化结果:体积由1.6M减少到932k(除了dll依赖);编译时长由4m20s左右,减到均为1m8s左右;webpack优化方式总结:1、优化模块查找路径2、剔除/精简不必要的、无用的模块3、设置缓存:缓存loader的执行结果(cacheDirectory/cache-loader)4、设置多线程:HappyPack/thread-loader5、dllplugin预编译#最后想偷偷的吐槽阿里的产品我一直很喜欢,语雀写文章还是挺不错的,但是不能引入外部图片这件事实在是太折磨我了,若自己上传图片,编译到自己的博客又防盗链,搞到现在都只想写纯文章,实在是不开心哦,虽然现在使用norefferer暂时解决了,鬼知道后面还会不会继续防呢,看来还是要用付费的东西一劳永逸嘤嘤嘤"},{"title":"记一次uglifyJsPlugin报错的问题","date":"2019-11-07T12:43:21.000Z","url":"/blog/2019/11/07/yuque/记一次uglifyJsPlugin报错的问题/","content":"这次碰到的问题十分简单,在前端项目使用uglifyJS压缩代码的时候报出错误:(webpack 4.x ,vue-cli3)网上查了一下uglify-js-plugin并不支持ES6+的代码,但是开发代码其实是有做babel转义的,报错的文件是在node_modules里的,于是我在new UglifyJsPlugin对node_modules里的代码进行过滤,再进行编译,就通过了。代码如下:这样就可以编译成功了。解决方法二:搜索问题的过程中有人说可以用terser-webpack-plugin 来压缩es6代码,readme上也说uglify-es已经不再做维护了,terser也是对uglifyJS的一个fork,可以放心使用。解决方法三:可以使用vue-cli3中的现代模式 进行开发,但是只针对支持es module的浏览器可用,而且<script type="module"> 需要配合始终开启的 CORS 进行加载,需要针对业务和使用场景使用。至于三种方法压缩后的代码体积,现代模式的方法会小一点,其余两种大一些且差不多,但是gzip之后基本一样。"},{"title":"记一次浏览器自动填充保存后密码问题","date":"2019-09-24T12:15:34.000Z","url":"/blog/2019/09/24/yuque/记一次浏览器自动填充保存后密码问题/","content":"问题描述接手一个前端历史项目的时候,发现页面中老是发现某些input[type=text]框自动填充浏览器保存过的用户名:(这个是Chrome展示出已经保存过的用户名&密码)(普通的输入框便自动填充了用户名)即使在input框中加上autocomplete=”off”属性,也还是会自动填充;问题出现场景只在Chrome浏览器,electron环境下的chromium倒不会,看来是浏览器保存密码机制影响到普通的input框了,这样十分影响用户体验。分析过程既然有之前保存过的用户名,那么页面上必定有type=”password”的input框,搜索后发现有五、六处都是保存密码标签,三处是修改密码的弹窗,仅使用display:none隐藏起来,即它是全局都在页面中的;剩下几处为登录弹窗,也是存在于全局中。经查资料发现,浏览器是在当前页面遇到type="text"与type="password"的,即使认为它没什么卵用。结果这么一试,居然成功了!果然是因为表单上没有加form,导致password表单作用域应用在全局,抓到哪个input就把它填充了,虽然怎么找的到现在都不清楚……亲测是页面组件中最后一个input,可能是认为它权重和password最接近吧。这个故事告诉我们,追求HTML5标准,除了可以解决SEO,也能让后期不会出现像上述这种比较耗时间又难排查的问题,后期改起来也不会那么束手束脚,以后开发的时候还是得留个眼,多多review一下,才能真正提升效率。关于自动填充的机制,本人水平有限,到现在还不是很清晰,如果以后有机会再碰到的话也可以深究一下。"},{"title":"web字体实践方案","date":"2019-05-22T06:24:36.000Z","url":"/blog/2019/05/22/yuque/web字体实践方案/","content":"Web字体是一种CSS特性,允许您指定在访问时随您的网站一起下载的字体文件,这意味着任何支持Web字体的浏览器都可以使用您指定的字体。引入方法很简单,在css文件中声明@font-face属性即可:目前主流的web字体格式有:woff、tff、otf、eot和svg等,但是浏览器支持情况不一,因此需要多种字体格式以获得更好跨环境支持,最好的方法就是在css声明多个字体源。(浏览器支持情况,打叉的都是支持)关于各种字体格式说明,可以在 这篇文章查阅。从这篇文章我们可以得出,woff才是未来web字体的主流,优点有更好的编码压缩(体积比ttf减少40%),加载速度更快,保护版权等小程序如何使用小程序也支持web字体图标,下面介绍它的引入方法亲测小程序不能引入本地路径的字体源,否则会报错;一种可用的方法是将字体文件转成base64:感觉这样引入也挺麻烦的,复制粘贴的时候也会有一定出错的几率。推荐使用阿里巴巴字体图标库,字体文件是挂在阿里cdn上,可以直接在协作网址上复制代码(推荐使用Unicode方法):而且在上面可以生成更新代码,通过文件后缀哈希值区分,不必担心缓存问题。一开始我担心小程序会不会不能访问第三方域名的文件,但是实测是ok的,这和background-image属性使用外部链接方式是一致的,不必担心这个问题。接下来就是使用这些图标了,我的使用方法是先声明公共class的font-family,再在每一个字体class的伪元素声明它自身的content内容,内容即是在下载到本地的css上说明的编码,这里会比较麻烦,但好处就是你可以定义自己的class名,使其更好的语义化;限制:小程序不支持多色图标小程序不支持标签,所以在正常浏览器环境也可以这么使用:// 内容为字体编码3字体图标有什么好处这里先说字体图标的好处,再说一下阿里iconfont字体图标库的使用上的好处&需注意的问题。1、web字体相对于png来说,最大的好处就是减少请求体积,特别是对移动端这种对性能优化要求比较大的情况来说,是占了绝大部分优势的。除优化性能,也减少了带宽。2、web字体解压读取更快,可以在同一图标中设置不同的颜色,若是png则需要两张图片及以上。3、字体图标为矢量图标,精度更高,放大多少也不会失真,png则可能会有锯齿问题。现在iconfont也支持多色图标了,但是具体支持多少种颜色目前没有详细说明关于iconfont的使用特点,我觉得最大的一点是方便了设计师和开发者的协作沟通,两方只需在同一平台上同步内容,减少im工具上的沟通,开发者若追溯也只用在git历史提交上查看,不必维护多个文件。iconfont也注重版权问题,只要设计师声明了版权,若发现有第三方盗用即可合理维权。但相应的我们要警惕在iconfont上商用其他图标带来的问题。还有就是现在推荐的iconfont登录账号是github,微博据说不断抽风,大家可根据自己需要使用。"},{"title":"hello world","date":"2019-05-05T11:00:58.000Z","url":"/blog/2019/05/05/yuque/hello world/","content":"这是第一篇从语雀发布的文章。提供一张花花。真美啊。branch测试"},{"title":"async await初步理解","date":"2019-01-21T00:00:00.000Z","url":"/blog/2019/01/21/async-await/","tags":["ES2015","async-await"],"categories":["学习笔记"],"content":"Promise和generator的语法糖async-await 是建立在 promise机制之上的,并不能取代其地位。基本语法基本概念async用来表示函数是异步的,定义的函数会返回一个promise对象,可以使用then方法添加回调函数。await 可以理解为是 async wait 的简写。await 必须出现在 async 函数内部,不能单独使用。await 后面可以跟任何的JS 表达式。虽然说 await 可以等很多类型的东西,但是它最主要的意图是用来等待 Promise 对象的状态被 resolved。如果await的是 promise对象会造成异步函数停止执行并且等待 promise 的解决,如果等的是正常的表达式则立即执行。实例举例说明啊,你有三个请求需要发生,第三个请求是依赖于第二个请求的解构第二个请求依赖于第一个请求的结果。若用 ES5实现会有3层的回调,若用Promise 实现至少需要3个then。一个是代码横向发展,另一个是纵向发展。接下来是async await的实现。错误处理注意并行处理await若是等到promise还在pending的状态时,就会停止下来。loading 确实是等待请求都结束完才清除的。但是你认真的观察下浏览器的 timeline 请求是一个结束后再发另一个的(若观察效果请发真实的 ajax 请求)那么,正常的处理是怎样的呢?await in for 循环await必须在async函数的上下文中的。async await 碰上 forEach在这个例子中,通过 forEach 遍历的将每一个数字都执行 multi 操作。代码执行的结果是:1 秒后,一次性输出1,4,9。这个结果和我们的预期有些区别,我们是希望每间隔 1 秒,然后依次输出 1,4,9;所以当前代码应该是并行执行了,而我们期望的应该是串行执行。问题原因:async 函数返回的是一个promise,而forEach是一个个回调函数,并立即执行,当执行到一个await关键字附近的时候,就会返回一个promise对象,async函数内部被冻结,等待await后面的异步表达式执行完后,再执行async函数内部的剩余代码。因此剧本一forEach时得到的是一堆的promise对象,而不是async函数内部的执行结果。async函数保证的是函数内部的await的顺序执行。那么也就能说明async在forEach中是有作用的,只是场景不对罢了。"}]