react-router学习笔记
author: @TiffanysBear
基本介绍
React Router
是完整的 React 路由解决方案
React Router
保持 UI 与 URL 同步。它拥有简单的 API 与强大的功能例如代码缓冲加载、动态路由匹配、以及建立正确的位置过渡处理。
基础部分
路由配置
index路由配置:添加首页,设置默认页面,使用 IndexRoute
1 | import { IndexRoute } from 'react-router' |
react-router学习笔记
author: @TiffanysBear
React Router
是完整的 React 路由解决方案
React Router
保持 UI 与 URL 同步。它拥有简单的 API 与强大的功能例如代码缓冲加载、动态路由匹配、以及建立正确的位置过渡处理。
index路由配置:添加首页,设置默认页面,使用 IndexRoute
1 | import { IndexRoute } from 'react-router' |
【转】Mobx React 最佳实践
转载自 https://juejin.im/post/5a3b1a88f265da431440dc4a
在这一篇文章里,将展示一些使用了mobx的React的最佳实践方式,并按照一条一条的规则来展示。在你遇到问题的时候,可以依照着这些规则来解决。
这篇文章要求你对于mobx的stores有基本的理解,如果没有的话请先阅读官方文档。
TypeScript学习笔记
author: @TiffanysBear
1、类型注解
2、接口interface:使用interface可以申明一个类型
3、类
1 | class Student { |
前端面试题
author: @TiffanysBear
2年工作经验出去接受社会的毒打,参与的前端社招的公司和题目的记录如下,后续可能还会有增加,先暂时记录这么多:
一面:
在一面之前先是做题,做题时间为40分钟,主要的笔试题和面试中涉及的部分包括以下:
FIS 插件机制
author: @TiffanysBear
当我们使用 FIS 插件的时候,有没有想过自己也开发一个基于 FIS 的插件,参与 FIS 打包编译的整个流程;那么问题就来了:
基于以下的问题,从原理再进行慢慢分析,了解 FIS 编译的基本流程和原理,以及如何自己自定义一个 FIS 插件。
fis的编译过程可以分为两个阶段: 单文件编译 和 打包。处理流程如下图,图片来自 FIS 官网:
重新理解前端系列 — AMD、CMD
author: @TiffanysBear
本文主要是针对之前一些熟悉的前端概念,再次回顾的时候,结合自己的开发经验和使用,进行再次理解。经过了开发和线上使用之后,会有更为深刻的印象。对比requirejs源码分析,实现一个模块加载器,需要考虑哪些问题。
其实对于AMD和CMD的不同,之前一直是拘泥在使用上的不同。没有深刻的认识为什么会有不同,其实主要是因为浏览器端和 Node 端不同性能特点和瓶颈带来的不同。
早期的js模块化主要用于浏览器端,主要的需求和瓶颈在于带宽,需要将js从服务端下载下来,从而带来的网络性能开销,因此主要是满足对于作用域、按需加载的需求。因此AMD(异步模块定义)的出现,适合浏览器端环境。
而后出现Node之后,主要的性能开销不再是网络性能,磁盘的读写和开销可以忽略不计;CMD的出现更符合Node 对于CommonJS的定义和理解,在运行时进行加载,引入时只是产生引用指向关系。
因此两者产生了不同的使用特点,在出现循环引用时,就产生了不同的现象。以下是针对 requirejs 源码部分的解读。如果有问题,欢迎提问纠正。
一先开始是需要判断环境,浏览器环境和webworker环境;如果是浏览器环境,通过document.createElement
创建script标签,使用async属性使js能进行异步加载, IE等不兼容async字段的,通过监听 load 、 onreadystatechange 事件执行回调,监听脚本加载完成。
1 | req.createNode = function (config, moduleName, url) { |
通过 setTimeout 放入下一个队列中,保证加载顺序
1 | //通过setTimeout的方式加载依赖,放入下一个队列,保证加载顺序 |
依赖数量,是通过 depCount 来计算的,通过循环遍历,统计具体的依赖数量;
1 | // ... |
判断单个文件加载成功,是通过 checkLoaded 每间隔 50s 做一次轮询进行判断,变量 inCheckLoaded 作为标识;下面是 checkLoaded 函数:
1 | function checkLoaded() { |
这部分暂且还有点疑惑,先mark一下,之后再理解;
看到有个 breakCycle 函数,执行条件是 needCycleCheck 为 true,但是当 !mod.inited && mod.fetched && map.isDefine
模块未被初始化完成,但是已经获取过定义过之后,且 在 map.prefix 有前缀,会启动 breakCycle 检查;至于为什么要这么做,只能猜测是为了到模块require时循环引用打破轮询查询加载状态等待的问题,现在先留一个疑问。
1 | function breakCycle(mod, traced, processed) { |
但是在CommonJs中时,存在依赖的情况下,因为存在的只是引用,代码执行是在实际调用时才发生,在文件的开头和结尾也会有变量标识是否加载完成。一旦某个模块出现循环依赖加载
,就只输出已经执行到的部分,还未执行的部分不会输出。
在ES6模块加载的循环加载情况下,ES6是动态引用的,不存在缓存值问题,而且模块里面的变量绑定所在的模块;不关心是否发生了循环加载,只是生成一个指向被加载模块的引用,需要开发者自己来保证真正取值的时候能够取到值。
Vue.js中watch的高级用法
转载自 https://juejin.im/post/5ae91fa76fb9a07aa7677543
author: Dunizb
在 Vue.js 的学习中,看到这篇文章,转载记录一下用作备忘。
假设有如下代码:
1 | <div> |
复制代码上面的代码的效果是,当我们输入firstName后,wacth监听每次修改变化的新值,然后计算输出fullName。
这里 watch 的一个特点是,最初绑定的时候是不会执行的,要等到 firstName 改变时才执行监听计算。那我们想要一开始就让他最初绑定的时候就执行改怎么办呢?我们需要修改一下我们的 watch 写法,修改过后的 watch 代码如下:
1 | watch: { |
从0到1发布一个npm包
author: @TiffanysBear
最近在项目业务中有遇到一些问题,一些通用的方法或者封装的模块在PC、WAP甚至是APP中都需要使用,但是对于业务的PC、WAP、APP往往是不同的业务、不同的代码库中,尽管已经将公用的组件和方法抽离到各自公共common中,但是各个大业务大方向上的公用封装依然不能满足需求。
比如一个计算文档类型大小的方法,可能都同时存在于各个业务的common中,假设是有3处代码库中均有;如果此时的需求是将文档类型或者大小的方法进行一些修改,增加一种文档类型或者减少一种文档类型,那咱们是否是需要去共同修改上面的3处方法。这样做,很不利于代码的维护,浪费人力,增加了代码工作量。
那么,如何做到管理一些公共依赖的基础模块代码呢?这时候,封装发布一个npm包进行统一管理就是一个很好的办法了。
先po一下我在写这篇文章时,根据以下的步骤发布的一个简单封装的npm包以及github地址,大家可以先看:
npm包:page-performance-monitor
github地址:page-performance-monitor,欢迎 star、issue
下面,就从0开始讲起,如何从0到1发布一个npm包。先介绍一下什么是npm~
npm 是JavaScript 世界的包管理工具,并且是Node.js 平台的默认包管理工具。通过npm 可以安装、共享、分发代码,管理项目依赖关系。
比如有一些非常通用的公用方法,抽象封装,剔除一些冗余的业务需求,可以封装在一个npm包中,提供给相应的多个业务去使用。
那么接下来就列举一下封装一个简单的封装步骤;
以我之前的博客中列举的页面性能监控工具performance为例,具体的performance介绍可以点击链接,做一个简单的封装,满足基本的业务上的打点统计需求即可;后面也会讲到后续如何去封装一个高质量的npm包,比如加上一些example、测试test、完善README.md等,逐步去完善。大概是有以下几个步骤:
1、新建项目,准备需要发布的代码
2、准备package.json
3、注册npm账号、并登录
4、发布
其实发布的过程并不难,要发布一个好的质量高的npm包往往是取决于要封装的代码、以及对代码单测覆盖、demo案例、README介绍等
开始准备的步骤,从一个最基础的项目新建开始,都是在Mac的Linux环境上进行:
1 | // 新建项目文件夹 |
1、先去官网注册一个账号,填写好账号、密码、邮箱
2、然后登录npm账号 npm login
,如果你们公司有自己的默认npm仓库或者使用的淘宝镜像,注意需要指定一下仓库地址;npm login --registry=https://registry.npmjs.org
1 | # 会依次让你输入用户名、密码、和邮箱 |
3、发布包 npm publish --registry=https://registry.npmjs.org
会提示+ page-performance-monitor@1.0.0 你的包名字和版本,那么说明就发布好了。
我在发布的时候遇到了两个小问题,记录一下,如果你们也有相同的问题,可以使用下面的解决办法:
1). 提示 publish Failed PUT 403
you must verify your email before publishing a new package: https://www.npmjs.com/email-edit : page-performance-monitor
之前登录的邮箱需要验证,去注册邮箱中找到npm发的邮件,点击验证一下就行.
2)第二个问题是:You do not have permission to publish “page-performance”. Are you logged in as the correct user? : page-performance
提示是说你没有权限发布这个包,其实是因为你的这个包名字和已有的重复了,需要在 package.json 里面换一个包名就行。
到这里,一个简单的npm包就封装好了,如何确认自己的包确认好了呢?去官网的搜索框输入你的包名搜一下,找到你的就ok啦~
到这步,你就会发布一个简单的npm包啦,如果只是一个很小的需求的化,就完全够用了;但是如果想要发布一个质量好有各种小标签logo的,那么就需要如下的步骤进行一下优化。
页面性能监测之performance
author: @TiffanysBear
最近,需要对业务上的一些性能做一些优化,比如降低首屏时间、减少核心按钮可操作时间等的一些操作;在这之前,需要建立的就是数据监控的准线,也就是说一开始的页面首屏数据是怎样的,优化之后的数据是怎样,需要有一个对比效果。此时,performance 这个API就非常合适了。
Performance 接口可以获取到当前页面中与性能相关的信息。它是 High Resolution Time API 的一部分,同时也融合了 Performance Timeline API、Navigation Timing API、 User Timing API 和 Resource Timing API。
该类型的对象可以通过调用只读属性 Window.performance 来获得。
参考链接 https://developer.mozilla.org/zh-CN/docs/Web/API/Performance
performance对象是全局的,它的timing属性是一个对象,它包含了各种与浏览器性能有关的时间数据,提供浏览器处理网页各个阶段的耗时。偷一个图~
performance.timing对象包含下列属性(全部只读):
navigationStart:当前浏览器窗口的前一个网页关闭,发生unload事件时的Unix毫秒时间戳。如果没有前一个网页,则等于fetchStart属性。
unloadEventStart:如果前一个网页与当前网页属于同一个域名,则返回前一个网页的unload事件发生时的Unix毫秒时间戳。如果没有前一个网页,或者之前的网页跳转不是在同一个域名内,则返回值为0。
unloadEventEnd:如果前一个网页与当前网页属于同一个域名,则返回前一个网页unload事件的回调函数结束时的Unix毫秒时间戳。如果没有前一个网页,或者之前的网页跳转不是在同一个域名内,则返回值为0。
redirectStart:返回第一个HTTP跳转开始时的Unix毫秒时间戳。如果没有跳转,或者不是同一个域名内部的跳转,则返回值为0。
redirectEnd:返回最后一个HTTP跳转结束时(即跳转回应的最后一个字节接受完成时)的Unix毫秒时间戳。如果没有跳转,或者不是同一个域名内部的跳转,则返回值为0。
fetchStart:返回浏览器准备使用HTTP请求读取文档时的Unix毫秒时间戳。该事件在网页查询本地缓存之前发生。
domainLookupStart:返回域名查询开始时的Unix毫秒时间戳。如果使用持久连接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值。
domainLookupEnd:返回域名查询结束时的Unix毫秒时间戳。如果使用持久连接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值。
connectStart:返回HTTP请求开始向服务器发送时的Unix毫秒时间戳。如果使用持久连接(persistent connection),则返回值等同于fetchStart属性的值。
connectEnd:返回浏览器与服务器之间的连接建立时的Unix毫秒时间戳。如果建立的是持久连接,则返回值等同于fetchStart属性的值。连接建立指的是所有握手和认证过程全部结束。
secureConnectionStart:返回浏览器与服务器开始安全链接的握手时的Unix毫秒时间戳。如果当前网页不要求安全连接,则返回0。
requestStart:返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的Unix毫秒时间戳。
responseStart:返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的Unix毫秒时间戳。
responseEnd:返回浏览器从服务器收到(或从本地缓存读取)最后一个字节时(如果在此之前HTTP连接已经关闭,则返回关闭时)的Unix毫秒时间戳。
domLoading:返回当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的readystatechange事件触发时)的Unix毫秒时间戳。
domInteractive:返回当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的Unix毫秒时间戳。
domContentLoadedEventStart:返回当前网页DOMContentLoaded事件发生时(即DOM结构解析完毕、所有脚本开始运行时)的Unix毫秒时间戳。
domContentLoadedEventEnd:返回当前网页所有需要执行的脚本执行完成时的Unix毫秒时间戳。
domComplete:返回当前网页DOM结构生成时(即Document.readyState属性变为“complete”,以及相应的readystatechange事件发生时)的Unix毫秒时间戳。
loadEventStart:返回当前网页load事件的回调函数开始时的Unix毫秒时间戳。如果该事件还没有发生,返回0。
loadEventEnd:返回当前网页load事件的回调函数运行结束时的Unix毫秒时间戳。如果该事件还没有发生,返回0。
一些值得思考的前端面试题
还在继续补充中……
author: @TiffanysBear
在nodejs开发的时候 处理过什么windows和mac的平台兼容性问题
设计一个方案,在浏览器中点击一个button,然后能在你的前端项目源码文件中增加一个index.js文件,如何实现?提供思路
用nodejs,将base64转化成png文件,或者将png文件转化为base64
如果你用nodejs实现的爬虫服务器的IP被指定网站封了,如何解封?
请设计一个方案:有a、b、c三个npm插件,它们会经常更新,在前端项目npm run start启动后,要求a、b、c三个npm插件自动更新到最新版本
大文件转存问题:服务器A有一个1000G的文件, 需要通过服务端B转发到服务端C,但是服务器B内存只有1个g, 怎么去实现这个大文件转存
如何劫持https的请求,提供思路
前端如何进行seo优化; 前后端分离的项目如何seo
简单实现async/await中的async函数
1000-div问题:一次性插入1000个div。
2万小球问题:在浏览器端,用js存储2万个小球的信息,包含小球的大小,位置,颜色等,如何做到对这2万条小球信息进行最优检索和存储
http的状态码中,499是什么?如何出现499,如何排查跟解决
proxy_ignore_client_abort on
;如何遍历一个dom树
new操作符都做了什么