Javascript
文章平均质量分 59
天猫精灵998
这个作者很懒,什么都没留下…
展开
-
从前端角度谈谈单页应用的 nginx 配置
有段时间没搞项目部署了,结果最近有同事在部署前端项目的时候,访问页面路由,响应都是 404,排查了半天,这里再总结一下。前端单页应用路由分两种:哈希模式和历史模式。哈希模式部署不会遇到啥问题,但是一般只用于本地调试,没人直接部署到生产环境。历史模式的路由跳转通过 pushState 和 replaceState 实现,不会触发浏览器刷新页面,不会给服务器发送请求,且会触发 popState 事件,因此可以实现纯前端路由。需要注意,使用历史模式的时候,还是有两种情况会导致浏览器发送请求给服务器:输入原创 2022-02-20 13:06:37 · 3355 阅读 · 1 评论 -
深入源码分析 file-loader 哈希生成规则
我们知道,在 Webpack 中有三种哈希:hash:一次 compilation 总体的哈希,只要有一个文件修改,整个哈希就会发生变化chunk-hash:根据 chunk 生成的哈希,同一个 chunk 中所有文件的哈希相同content-hash:根据文件内容生成的哈希在 Vue-cli 默认 Webpack 配置中,对 JS 启用 chunk-hash,CSS 启用 content-hash,而图片和字体文件则是 hash。这样就产生一个问题,修改 JS 代码后,图片和字体的哈希是否会发原创 2022-02-05 22:56:55 · 996 阅读 · 0 评论 -
如何使用 express 和 webpack-dev-middleware 搭建开发服务器
在开发前端项目时,我们一般会选用 webpack-dev-server 作为开发服务器,例如:// webpack.config.jsmodule.exports = { // ... devServer: { static: './dist', },}// package.json{ "scripts": { "serve": "webpack serve --open", "build": "webpack" },}但实际上 Webpack原创 2022-02-05 20:53:16 · 1355 阅读 · 0 评论 -
如何使用 chrome devtool 分析前端代码执行耗时和内存占用
如何分析代码执行耗时代码执行耗时这块,大家应该都知道使用 Performance 面板中的 火焰图,火焰图中每个方块的宽度代表执行耗时,方块叠加的深度代表调用栈的深度。通过火焰图可以很直观地展示出代码调用关系,当你不熟悉某个框架、源码中的代码逻辑,又不希望一行行去看源码,火焰图就是最好的工具。在分析性能的时候,为排除插件的影响,需要启用无痕模式此外我们还可以看到每一行代码执行的时间。在火焰图中找到长任务,点击顶部 Task,点击 Button-Up,这时候可以看到根据耗时列出的调用栈:找到那个原创 2022-01-31 13:11:30 · 3993 阅读 · 0 评论 -
如何使用 Map 实现 Set
关于 Map 和 Set 是两个抽象数据结构,Map 存储一个键值对集合,其中键不重复,Set 存储一个不重复的元素集合。本质上 Set 可以视为一种特殊的 Map,Set 其实就是 Map 中的键。这里我们用 TypeScript 使用 Map 来实现 Set。核心的思路非常简单,创建一个 Map,我们只要用 Map 的键就行,键对应的值全部填充 undefined:class NewSet<T extends unknown> { private collection: Map<原创 2022-01-23 12:38:24 · 1016 阅读 · 0 评论 -
Nodejs 使用 Buffer 将图片转为 base64
一直以为图片转为 base64 很复杂,结果今天看了下 Docusaurus 的 plugin-ideal-image 插件源码,居然只要一行代码就完事了:const toBase64 = (extMimeType: string, data: Buffer): string => `data:${extMimeType};base64,${data.toString('base64')}`;这里说明下,这个插件使用 sharp 对图片进行处理,最后返回的是一个 Buffer 实例,我们先来原创 2022-01-22 23:33:30 · 7144 阅读 · 0 评论 -
如何编写一个 Vue 权限控制指令
在业务中经常会遇到权限管理的问题,例如按钮级别或者页面内操作权限的需求,我们可以编写一个全局自定义指令。例如我们可以将指令直接注册到 main.js 中:import Vue from "vue";import App from "./App.vue";Vue.directive("auth-key", { inserted(el, binding) { // ... }})new Vue({ render: h => h(App),}).$mount("#app");这原创 2022-01-16 20:38:19 · 475 阅读 · 0 评论 -
webpack-dev-server 如何配置代理
在 CRA 搭建的项目中,我们知道可以在 src/setupProxy.js 文件中写入代理配置:const proxy = require('http-proxy-middleware');module.exports = function(app) { app.use( proxy( '/course', { target: 'localhost:8080', changeOrigin: true, }, ),原创 2022-01-15 11:26:52 · 1335 阅读 · 0 评论 -
ES6 Set 和 Map 遍历操作
作为 ES2015 的新增特性,Set 和 Map 对象大家应该很熟悉了,例如 Set 在数组去重等场景中经常会用到:function unique(array = []) { return Array.from(new Set(array));}但是一般我们都是只在需要这种数据结构的时候才去创建它,在用完之后就转回数组。大家可能都认为,相比 Set 、Map 对象,还是数组操作更熟悉一些。但实际上它们本身也提供了一些遍历方法,下面我们一起来看下。Set 对象遍历操作Set 结构的实例有四个遍原创 2022-01-09 17:58:35 · 2289 阅读 · 0 评论 -
如何覆盖 CRA 默认 webpack 配置
在 CRA 创建的项目中,经常需要修改默认 webpack 配置。但是 CRA 不像 Vue-cli 可以提供自定义 webpack 配置,而 eject 又会把全部配置暴露出来,很麻烦。这种情况下可以使用 react-app-rewired 这个库:$ yarn add react-app-rewired -D在项目根目录创建一个 config-overrides.js 文件,添加自定义 webpack 配置:/* config-overrides.js */module.exports =原创 2022-01-09 12:43:57 · 1017 阅读 · 0 评论 -
ES 新语法:`Array.prototype.groupBy`
在开发中经常需要对数据进行分组,但是由于没有原生方法的支持,我们自己实现的数据分组函数通常都比较冗长而且难以理解。不过,告诉大家一个好消息,一个专门用来做数据分组的提案 Array.prototype.groupBy 已经到达 Stage 3 啦!在看这个提案,之前,我们先来回顾下我们以前在 JavaScript 里是怎么分组的。以前的方式假设我们有下面一组数据:const items = [ { type: 'clothes', value: '????', },原创 2021-12-27 22:38:48 · 761 阅读 · 0 评论 -
JS、Java、Go 实现反转一维数组
Java 实现:public class ReverseArray { public void reverse(int[] arr) { int i = 0, j = arr.length - 1; while (j > i) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; i++;原创 2021-12-25 18:17:46 · 662 阅读 · 0 评论 -
记一次 Vue 项目代码优化
项目中有一个需求,在切换视频播放源之后,需要恢复之前设置的播放速率。经过试验发现,如果在切换播放源之后,立即设置播放速率是不生效的,需要在视频加载完成之后设置才生效,因此这边需要切换播放源的时候保存一个回调,在 onPlay 事件触发的时候设置播放速率:import bus from "EventBus";export default { data() { return { rateChangeEvent: null; } }, mounted() { bus.$on('onP原创 2021-12-16 20:52:26 · 128 阅读 · 0 评论 -
GitHub Pages 配合 GitHub Actions 实现文档网站自动部署
最近在用 docusaurus 做一个文档网站,通过 GitHub Pages 进行部署,每次部署的时候,需要在本地执行构建命令,然后将构建产物提交到 GitHub 上面,比较麻烦。因此这边用了 GitHub Action 实现持续集成。持续集成由很多操作组成,比如拉取代码、执行测试用例、登录远程服务器,发布到第三方服务等等。GitHub 把这些操作就称为 actions。我们先来了解一下一些术语:workflow(工作流程):持续集成一次运行的过程,就是一个 workflow。job(任务):一原创 2021-12-12 22:15:29 · 1807 阅读 · 0 评论 -
如何调试线上项目的代码
我们知道,通常生产环境的前端代码是经过混淆压缩的,代码本身难以阅读,但有时候排查线上 bug 需要对线上项目的代码进行调试。那么如何调试线上项目的代码呢?这边介绍两种方法。直接调试我们知道,生产环境通常会使用 uglifyJS 或者 terser 进行混淆压缩,但是这些压缩工具并不会做程序流分析,因此并不是所有的变量名、方法名都会被压缩。例如模块中有一个向外导出的方法,为确保其他模块能正常调用,这个方法名不会做混淆处理,只有该模块内部的变量名、方法名才会混淆压缩。或者在代码中的字符串字面量,也不会进行压原创 2021-12-11 21:34:15 · 1869 阅读 · 0 评论 -
“用 Promise.then 容易出现回调地狱,所以改用 async/await” 这个说法对吗
昨天周会同事做技术分享,讲到一点:“用 Promise.then 容易出现回调地狱,所以改用 async/await”。那么这个说法对吗?首先这个说法完全错误。“Promise.then 出现回调地狱”,完全是编码不规范的问题,而不是 api 的问题。来看下面这个例子:// 解析压缩包function parseZip(zip) { return new Promise( resolve => setTimeout(resolve, 1000, zip) );}// 从压缩原创 2021-12-11 14:50:39 · 1209 阅读 · 0 评论 -
浅谈 Vue3 中的 v-model 和 sync 修饰符
很多同学对 Vue 的第一印象就是“响应式”、“双向绑定”等特性,而 v-model 就是实现双向绑定的语法糖,用过 Vue 的小伙伴一定都非常熟悉。但是在 Vue3 中,v-model 发生了一些改动,使得它不再兼容 Vue2 的用法,具体是什么呢,我们一起来看看。非兼容:用于自定义组件时,v-model prop 和事件默认名称已更改:prop:value -> modelValue;事件:input -> update:modelValue;非兼容:v-bind 的 .sync原创 2021-12-06 23:53:36 · 8603 阅读 · 0 评论 -
Jest 单元测试快速入门
测试的类型单元测试集成测试端到端测试(E2E)测试 React 组件需要解决两个关键问题怎么渲染待测试组件;怎么测试渲染出来的组件;浅层渲染对于组件渲染,Airbnb 作为重度使用 React 的先驱,早就提出了专门的解决方案:Enzyme$ npm install enzyme enzyme-adapter-react-16Enzyme 提供的一个重要功能便是组件的浅层渲染(Shallow Rendering)。它允许我们在运行测试时,只渲染父组件而不渲染其所有的子组件。浅层原创 2021-11-17 16:31:32 · 608 阅读 · 0 评论 -
Webpack 模块方法——require.context
在 Webpack 中,除了可以使用 import 、export 等模块语法之外,还可以使用 Webpack 提供的模块方法。其中使用最多的是 require.context 。在项目中经常会遇到一个问题,组件库导入、路由注册等需要手写大量 import ,比较麻烦。这种情况下就可以使用 require.context 。require.context( (directory: String), // 检索目录 (includeSubdirs: Boolean), // 是否检索子文件夹,默认原创 2021-11-13 21:08:37 · 1153 阅读 · 0 评论 -
面试官:什么时候不能使用箭头函数
今天看到这个面试题,特别有意思。一般来说面试官应该问的是箭头函数和普通函数的区别,这样应该大多数人都能答得上来,但是现在反过来,考验逆向思维,很多人可能都一下子反应不过来。我们先来回顾一下箭头函数和普通函数的区别:箭头函数没有自己的 this ,没有 argument 对象,没有 prototype ,不能作为构造函数(用 new 调用会报错)。箭头函数会自动捕获上级词法作用域的 this ,并且箭头函数的 this 在声明的时候就已经确定了,不能通过 call 或者 apply 修改。因此以下场景不原创 2021-11-08 22:22:13 · 1260 阅读 · 0 评论 -
手写一个简单的静态资源服务器
写了一个简单的静态资源服务器,如果文件不存在或者路径是一个目录,则返回错误信息。这里有两个特点:使用 async-to-js 进行异常处理;使用 stream ,通过 pipe 方法将 Readable 写入到 Writable ,避免 Readfile 方法一次性将整个文件加载到内存中;后期需要在响应头中加上 Content-Type 。const http = require("http");const path = require("path");const fs = require(原创 2021-10-29 20:30:25 · 116 阅读 · 0 评论 -
谈谈 React 自动批处理
使用 React Hooks 的时候很多人会遇到一个问题,调用 set 方法之后,立即获取状态发现还是老的状态:const App: React.FC<{}> = () => { const [count, setCount] = React.useState(0); const handleClick = () => { setCount(val => val + 1); console.log(count); // 0 } return ( <原创 2021-10-23 22:42:55 · 416 阅读 · 0 评论 -
你不知道的 JS 代码小技巧
总结了一些开发常用的 JS 小技巧,让你的代码更优雅!1. 通过条件判断给变量赋布尔值先来看一段代码:handleFormChange(e) { let isUpload; if (e.target.value === 'upload') { isUpload = true; } else { isUpload = false; }}在项目中很多同事都会这样写,但实际上 == 和 === 的表达式可以直接给变量赋值:handleFormChange(e) {原创 2021-10-19 20:29:27 · 131 阅读 · 0 评论 -
如何搭建一个 npm 私服
最近在开发一个脚手架工具,但是在开发调试阶段不能发布到 npm 官方仓库上,而且后期也只希望在部门内部使用,因此就有了搭建 npm 私服的需求。虽然 npm 官方提供收费的私有仓库,考虑到现在项目需求,使用 verdaccio 不仅免费而且还简单好用。如何安装使用下面的命令全局安装:# 使用 npm$ npm i verdaccio -g# 使用 yarn$ yarn global add verdaccio...原创 2021-10-16 18:43:08 · 594 阅读 · 0 评论 -
ubuntu 安装 LTS 版本 Node.js
今天在阿里云服务器上安装 Node.js ,用了下面的命令:$ sudo apt-get update$ sudo apt-get install nodejs结果看了下安装的版本居然是 10.x 的,现在 LTS 版本都是 14.x 了,怎么才能安装 LTS 版本呢?网上搜了下可以在安装的时候指定版本:$ sudo apt install nodejs=14.18.1但是执行却提示找不到版本:Version ‘14.18.1’ for ‘nodejs’ was not found又到原创 2021-10-16 17:34:08 · 918 阅读 · 0 评论 -
从 async/await 看 redux-saga 原理
最近看了一篇神光大佬的文章:为什么 redux-saga 不能用 async await 实现 ,看完之后深有体会。虽然这篇文章没有讲具体实现原理,但是总结了两个浅显易懂的道理:async/await 本质上是一个 generator 的自动执行器,没有 runtime 逻辑;saga 实际上也是实现了 generator 执行器,但是有自己的 runtime ,可以将异步过程抽离出来,便于测试;那么很显然,搞懂 async/await 原理,redux-saga 的原理自然也就搞清楚了。1.原创 2021-10-12 20:34:47 · 280 阅读 · 0 评论 -
你会用 markdown ,那你会部署文档网站吗
相信大家平时都会用 markdown 编写文档,特别是配合 Typora 使用非常方便。但很多时候我们不满足于本地文档,而是要把文档做成在线的形式,这样如果内容更新,团队成员都可以及时看到。那么其实用来生成静态网站的开源项目也有不少,例如 VuePress ,Docsify 等,特别是 VuePress 已经广泛用于 Vue 官方文档在内的各种文档的部署。但是 VuePress 是基于 Vue 的,而本人现在团队主要使用 React 技术栈,于是采用了和 VuePress 类似的由 facebook 团队原创 2021-10-10 17:02:57 · 1158 阅读 · 0 评论 -
设计模式系列:从实际项目需求谈谈代理模式/装饰器模式
问题引入在项目中有一个需求,某个方法的执行需要加上权限判断:const clusterExapnd = () => { console.log("集群扩容操作");}相信很多人一定都会这样写:const clusterExapnd = () => { if (loginUser !== "admin") { console.log("当前用户没有操作权限!"); return; } console.log("集群扩容操作");}在上面这个简单的场景中,这样写原创 2021-09-26 20:33:12 · 190 阅读 · 0 评论 -
设计模式系列:策略模式
昨天在调试同事开发的页面,发现有很多 404 的请求,看了下 Network 面板有点哭笑不得,原来是前端把页面路由当成后台接口请求了,后台肯定不存在对应的资源,因为是前端路由。那么为什么会发送这样的请求呢?我看了下同事写的代码,由于这边的需求是需要同时支持 mock 环境和正常后台环境,然后根据传递的 query 字段选择合适的接口进行请求。然鹅看到代码就惊呆了,各种 IF ELSE 和 SWITCH CASE ,夸张的是同事告诉我这是他能想到的最优方案(手工狗头)const isMockEnv =原创 2021-09-25 12:36:46 · 248 阅读 · 0 评论 -
Chrome devtool 火焰图的看法
我们知道某个函数的执行路径是有 call stack 的,可以看到从哪个函数一步步调用过来的,是一条线。但其实这个函数调用的函数并不只一个,可能是多个:调用栈只是保存了执行到某个函数的一条路线,而火焰图则保存了所有的执行路线。所以你会在火焰图中看到这样的分叉:其实就是这样的执行过程:来算一道题:函数 A 总耗时 50 ms,它调用的函数 B 耗时 10 ms,它调用的函数 C 耗时 20 ms,问:函数 A 的其余逻辑耗时多少 ms?很明显可以算出是 50 - 10 - 20= 20原创 2021-09-23 19:31:22 · 600 阅读 · 0 评论 -
React 引入 @vue/reactivity 实现响应式状态管理
看了 ssh 大佬的一篇文章,觉得挺有意思,刚好最近也在研究全局数据流方案,因此根据大佬的思路自己也尝试了一下。vue-next 是 Vue3 的源码仓库,Vue3 采用 lerna 做 package 的划分,而响应式能力 @vue/reactivity 被划分到了单独的一个 package 中。这个包提供了几个核心 api :effecteffect 是一个观察函数,它的作用是 收集依赖 。effect 接受一个函数,这个函数内部对于响应式数据的访问都可以收集依赖,在响应式数据更新之后,就会触发原创 2021-09-10 13:14:37 · 1602 阅读 · 0 评论 -
Node 中的 ReadStream 和 WriteStream
之前看别人用 Koa 实现文件下载功能,直接将 Readable Stream 传给 ctx.body :const fs = require('fs');const Koa = require('koa');const app = new Koa();app.use(async ctx => { try { ctx.body = fs.createReadStream(resolve(__dirname, 'test.json')); } catch (err) {原创 2021-09-08 14:50:35 · 1318 阅读 · 0 评论 -
基于发布订阅模式实现 time 和 timeEnd 方法
相信很多同学都用过 console.time 和 console.timeEnd 方法统计代码运行时间。这边本人利用发布订阅模式模拟实现 time 和 timeEnd 方法,代码如下:class MyConsole { constructor() { // 全局事件中心 // 采用先订阅后发布的模式 this.events = {}; } time(s) { let timeStart = new Date().getTime(); // 订阅事件原创 2021-08-24 13:39:10 · 207 阅读 · 0 评论 -
React Suspense 在异步获取数据方面的应用
写这篇文章之前,实在想吐槽一下 React 官方文档,很多 API 的介绍都是不明不白的,不看之前有一堆问号,看完之后问号更多了。项目需求最近在开发一个大数据运维的项目,需要展示大量的 echarts 图表。由于从后台调接口返回数据需要时间,然后前端对数据的处理也需要时间,这样就导致了页面加载的延迟。希望可以做一个整页的 loading ,在图表渲染完成之后展示图表内容。最近在看 ssh 大佬写的一篇文章:React Suspense + 自定义Hook开启数据请求新方式看完之后深受启发,希望可以借原创 2021-08-22 23:34:56 · 1079 阅读 · 0 评论 -
TS如何获取第三方库未导出的 Type
在使用 antd 组件的时候,同事遇到一个问题,Radio 组件的 onChange 事件处理函数,传递的参数是一个事件对象,无法推导类型:import { Radio } from "antd";import * as React from "react";type Props = { name: string;}const HelloWorld: React.FC<Props> = ({ name }) => { const [value, setValue]原创 2021-08-12 23:28:36 · 1749 阅读 · 0 评论 -
JS 时间格式化 api 的性能问题
哪种时间格式化 API 的性能最好,原生 API 性能一定好于第三方库吗发现问题在项目中有一个需求,需要绘制 CPU 占用和时间关系的 line chart ,数据量在几万到几十万级别。由于后台返回的是时间戳,需要在前端进行格式化。在前端进行时间格式化,下面几种都是常用的 API :// 使用 moment 第三方库moment(new Date()).format("hh::mm");// 使用 getHours + getMinuteslet now = new Date();[now.原创 2021-08-16 21:09:20 · 305 阅读 · 0 评论 -
TypeScript 使用 infer 实现类型推断
首先从一个问题引入,我们怎样拿到下面 Promise 内部包裹的类型呢?function request(req: string): Promise<string> { return new Promise(resolve => setTimeout(() => resolve(req), 3000))}很多同学上来就用 typeof 和 ReturnType 一把梭哈:type Request = typeof request; // type Request =原创 2021-08-16 11:29:40 · 1188 阅读 · 0 评论 -
yarn 包管理工具的使用
yarn 是什么“Yarn是由Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具 ,正如官方文档中写的,Yarn 是为了弥补 npm 的一些缺陷而出现的。”这句话让我想起了使用npm时的坑了:npm install的时候巨慢。特别是新的项目拉下来要等半天,删除node_modules,重新install的时候依旧如此。同一个项目,安装的时候无法保持一致性。由于package.json文件中版本号的特点,下面三个版本号在安装的时候代表不同的含义。原创 2021-08-14 18:15:30 · 485 阅读 · 0 评论 -
vscode主题样式配置
安装一下这个主题:整体风格和 WebStorm 类型,同时还支持快捷键,例如输入 log 按 TAB 会自动生成 console.log() 。VS Code 默认代码选中高亮效果一般,可以在 setting.json 中修改默认配置:"workbench.colorCustomizations": { "editor.lineHighlightBackground": "#00000090", "editor.lineHighlightBorder": "#ffffff30"},原创 2021-08-11 11:34:53 · 738 阅读 · 0 评论 -
深拷贝如何解决循环引用的情况
在看 Vuex 源码的时候看到里面有个 deepCopy 的实现,里面解决了循环引用的问题。本人对源码进行了优化,一起看一下是怎么实现的:function deepCopy (obj, cache=[]) { // 结束递归 if (obj === null || typeof obj !== 'object') return obj // 缓存命中,说明存在循环引用的情况 var hit = cache.filter(c => c.original === obj)[0];原创 2021-07-29 23:04:47 · 896 阅读 · 1 评论