前言 在阅读 utility-types 源码中发现了一段代码: // export type Falsy = false | '' | 0 | null | undefined; export const isFalsy = (val: unknown): val is Falsy => !val; 这里的返回类型不应该是 boolean 吗? 为什么要使用 val is Falsy? type guard 看到网上有这样一个例子: function isString(test: any): boolean { return typeof test === "string"; } function example(foo: any){ if(isString(foo)){ console.log("it is a string" + foo); console.log(foo.length); // string function } } example("hello world"); 在这种情况下,返回类型定义为 boolean 和 test is string 其实没有区别。但是如果这个时候不小心在 if 中调用了一个不存在的方法会怎么样呢?例如:...
基于 Web Components 跨框架组件开发
什么是 Web Components Web Component 并非单一的技术,而是由一系列 W3C 定义的浏览器标准组成,使得开发者可以构建出浏览器原生支持的组件。这些标准包括: Custom Elements:带有特定行为且用户自命名的 HTML 元素 Shadow DOM:对标签和样式的一层 DOM 包装 HTML Templates:可复用的 HTML 标签,提供了和用户自定义标签相结合的接口 Custom Elements Web component 提供了自定义标签的方法,可以通过 CustomElementRegistry.define() 方法用来注册一个 custom element,该方法接受以下参数: 表示所创建的元素名称的符合 DOMString 标准的字符串。custom element 的名称不能是单个单词,且其中必须要有短横线。 用于定义元素行为的类 。 可选参数,一个包含 extends 属性的配置对象,是可选参数。它指定了所创建的元素继承自哪个内置元素,可以继承任何内置元素。 customElements.define('my-element', WordCount, { extends: 'p' }); custom elements 可以分为两种: Autonomous custom elements 是独立的元素,它不继承其他内建的HTML元素。可以直接写成HTML标签的形式,或者是在js中使用:document.createElement("my-element")。 Customized built-in elements 继承自基本的HTML元素。在创建时,你必须指定所需扩展的元素(正如上面例子所示),使用时,需要先写出基本的元素标签,并通过 is 属性指定custom element的名称<p is="my-element">, 或者 document.createElement("p", { is: "my-element" })。 Shadow DOM Shadow DOM 可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更加干净、整洁。Shadow DOM 允许将隐藏的 DOM 树附加到常规的 DOM 树中——它以 shadow root 节点为起始根节点,在这个根节点的下方,可以是任意元素,和普通的 DOM 元素一样。 Shadow host:一个常规 DOM节点,Shadow DOM 会被附加到这个节点上。 Shadow tree:Shadow DOM内部的DOM树。 Shadow boundary:Shadow DOM结束的地方,也是常规 DOM开始的地方。 Shadow root: Shadow tree的根节点。 <my-element name="web component"></my-element > <script> class MyElement extends HTMLElement { connectedCallback() { const shadow = this....
React Server Components 介绍
2020年12月21日 React 官方公布了一个新的提案 React Server Component(后面简称:RSC),并做了视频介绍和 demo (如果跑不起来建议尝试docker)演示。React Server Component 还在研发中,目前还是个试验性的功能,主要目的是为了从社区收到一些反馈。离正式发布还需要较长时间,暂时不用立即跟进学习。接下来主要做个简单的介绍。 Web 渲染的演化 一、Web1.0 服务端渲染 为了区分目前常说的“服务端渲染”,暂且把没有 Ajax 时代的服务端渲染称为“Web1.0 服务端渲染”。Web1.0 的时候前后端不分离,后端提供数据和模板渲染相应 HTML 页面,前端主要提供页面样式和js实现交互动效果。 渲染流程: 客户端发起页面请求 服务端查询数据并使用相应的模板引擎渲染成 HTML 片段 客户端收到返回 HTML 解析成可见网页内容 优点: 友好的 SEO,每个页面都是服务端返回的完整的 HTML 首屏加载快,页面由后端渲染完成 缺点: 前后端耦合严重,前后端开发相互依赖 交互体验不佳,每个路由都需要页面刷新 服务端负载压力大,渲染任务都由服务端也丧失了客户端作为天然分布式系统的优势 二、客户端渲染(CSR) 随着前端页面复杂程度加剧和 Web2.0 Ajax 技术的发展,就有了前后端分离概念。以 Anglular 为代表的现代前端框架让这种后端提供接口,前端渲染页面的开发方式得到普及。也让服务端和客户端职责得到了明确的分工,让客户端和服务端各自实现更擅长的事情。 渲染流程: 客户端发起请求并接收返回的 HTML 内容 客户端解析网页内容并执行 JS 脚本 JS 利用 Ajax请求后端数据(json/xml) JS 动态将数据渲染在页面中 优点: 前后端分离模式,前端专注于UI,后端专注于逻辑 良好的交互体验,局部进行刷新,可以实现单页应用,预加载等提升页面性能 降低服务器压力,部署比较简单节约服务器成本 缺点: 不利于 SEO,页面数据都是动态生成不利于 SEO 优化 首屏白屏,首次请求几乎空白的 HMTL 页面,TTI受限于数据获取和浏览器渲染的耗时 三、服务端渲染(SSR) 随着单页应用的发展,不友好的 SEO 和首屏渲染白屏等问题亟待解决,于是再次考虑引入服务端渲染。主要逻辑是将 Web1....
浏览器缓存机制
前言 在前端开发中,性能一直都是被大家所重视的一点,然而判断一个网站的性能最直观的就是看网页打开的速度。其中提高网页反应速度的一个方式就是使用缓存。缓存技术一直一来在WEB技术体系中扮演非常重要角色,是快速且有效地提升性能的手段。 一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。 所以,缓存技术是无数WEB开发从业人员在工作过程中不可避免的一大问题。在产品开发的时候我们总是想办法避免缓存产生,而在产品发布之时又在想策略管理缓存提升网页的访问速度。了解浏览器的缓存命中原理,是开发WEB应用的基础,本文着眼于此,学习浏览器缓存的相关知识,总结缓存避免和缓存管理的方法,结合具体的场景说明缓存的相关问题。希望能对有需要的人有所帮助。 WEB缓存体系 在实际WEB开发过程中,缓存技术会涉及到不同层、不同端,比如:用户层、系统层、代理层、前端、后端、服务端等,每一层的缓存目标都是一致的,就是尽快返回请求数据、减少延迟,但每层使用的技术实现是各有不同,面对不同层、不同端的优劣,选用不同的技术来提升系统响应效率。所以,我们首先看下各层的缓存都有哪些技术,都缓存哪些数据,从整体上,对WEB的缓存技术进行了解,如下图所示: 本篇文章重点讲的就是上面红色框部分缓存内容。 认识浏览器缓存 当浏览器请求一个网站的时候,会加载各种各样的资源,比如:HTML文档、图片、CSS和JS等文件。对于一些不经常变的内容,浏览器会将他们保存在本地的文件中,下次访问相同网站的时候,直接加载这些资源,加速访问。 这些被浏览器保存的文件就被称为缓存(不是指Cookie或者Localstorage)。 那么如何知晓浏览器是读取了缓存还是直接请求服务器?如下图网站来做个示例: 第一次打开该网站后,如果再次刷新页面。会发现浏览器加载的众多资源中,有一部分 size 有具体数值,然而还有一部分请求,比如图片、css 和 js 等文件并没有显示文件大小,而是显示了 from dis cache 或者 from memory cache字样。这就说明了,该资源直接从本地硬盘或者浏览器内存读取,而并没有请求服务器。 浏览器启用缓存至少有两点显而易见的好处:(1)减少页面加载时间;(2)减少服务器负载; 浏览器是否使用缓存、缓存多久,是由服务器控制的。准确来说,当浏览器请求一个网页(或者其他资源)时,服务器发回的响应的「响应头」部分的某些字段指明了有关缓存的关键信息。下面看下,HTTP 报文中与缓存相关的首部字段: 通用首部字段(就是请求报文和响应报文都能用上的字段) 请求首部字段 响应首部字段 实体首部字段 浏览器缓存机制 根据上面四种类型的首部字段不同使用策略,浏览器中缓存可分为强缓存和协商缓存: 1)浏览器在加载资源时,先根据这个资源的一些 http header 判断它是否命中强缓存,强缓存如果命中,浏览器直接从自己的缓存中读取资源,不会发请求到服务器。比如:某个 css 文件,如果浏览器在加载它所在的网页时,这个 css 文件的缓存配置命中了强缓存,浏览器就直接从缓存中加载这个 css,连请求都不会发送到网页所在服务器; 2)当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外一些 http header 验证这个资源是否命中协商缓存,如果协商缓存命中,服务器会将这个请求返回,但是不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源,于是浏览器就又会从自己的缓存中去加载这个资源; 3)强缓存与协商缓存的共同点是:如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;区别是:强缓存不发请求到服务器,协商缓存会发请求到服务器。 4)当协商缓存也没有命中的时候,浏览器直接从服务器加载资源数据。 强缓存:Expires & Cache-Control 当浏览器对某个资源的请求命中了强缓存时,返回的 HTTP 状态为200,在 chrome 的开发者工具的 network 里面 size 会显示为 from cache,比如:京东的首页里就有很多静态资源配置了强缓存,用 chrome 打开几次,再用 f12 查看 network,可以看到有不少请求就是从缓存中加载的:...
JavaScript 任务和事件循环
js是单线程的,处理任务是一件接着一件处理,所以如果一个任务需要处理很久的话,后面的任务就会被阻塞,所以 JS 通过 Event Loop 事件循环的方式解决了这个问题。 First 首先来看下面一段代码: console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0); Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); 这段代码打印的结果是:'script start', 'promise1', 'promise2', 'setTimeout' 执行栈 js引擎开始运行代码的时候,会将代码压入执行栈进行执行: function a() { console.log('a'); } function b() { a(); } function c() { b(); } c(); 当代码被解析后,函数会依次被压入到栈中 当函数c执行完,开始出栈 事件循环 当执行栈中出现异步代码会怎么样? console.log("sync"); $.on('button', 'click', function onClick() { setTimeout(function timer() { console.log('You clicked the button!'); }, 2000); }); setTimeout(function timeout() { console.log("Click the button!...