前言
先占个坑,后期会把 JavaScript权威指南第七版和JavaScript高级程序设计第四版两本书读过一遍以后,写一下
可能会一章一章的仔细写,也可能只会写不明白的重点、难点,毕竟这两本书太厚了(笑哭)
先占个坑,后期会把 JavaScript权威指南第七版和JavaScript高级程序设计第四版两本书读过一遍以后,写一下
可能会一章一章的仔细写,也可能只会写不明白的重点、难点,毕竟这两本书太厚了(笑哭)
浏览器初次加载会完整的走过整个流程,但是之后我们可以对这个流程进行优化,避免非必要的流程
详细的回流重绘见下一篇文章
重新布局被称为reflow 回流,重新绘制被称为repaint 重绘
reflow
), 布局引擎为frame
计算图形, 以确定对象位置, 浏览器根据各种样式来计算结果放在它该出现的位置.回流
发生的一些因素:CSS
伪类,比如 :hover
class
属性DOM
offsetWidth
和offsetHeight
属性repaint
), 当计算好盒子模型的位置, 大小以及其他属性后, 浏览器就根据各自的特性进行绘制一遍, 显现出来给用户看color
或者 background
发生了变化,那就该给触发重绘的元素化化妆,化成它想要的样子。回流与重绘两者之间的联系在于: 触发回流一定会触发重绘, 而触发重绘却不一定会触发回流。
详细介绍见 https://segmentfault.com/a/1190000014520786
淘宝团队的文章 https://fed.taobao.org/blog/taofed/do71ct/performance-composite/
提升到合成层的最好方法就是 用 transfrom + opacity 搭配 will-change
京东和淘宝的轮播容器都是采用opacity + transform 3d
1 | opacity: 1; |
一帧的声明周期
防抖应用,按照实际帧数触发
1 | let flag = false; |
案例: react 16 通过rAF 模拟 rIF 进行事件调度
下图是rAF 和 rIF 的不同
简单记录工具的本地化,可以跳过
1 | npm install -g lighthouse |
拉取镜像
1 | docker pull webpagetest/server |
运行实例
1 | docker run -d -p 4000:80 --rm webpagetest/server |
创建server目录
1 | mkdir wpt-mac-server |
创建Dockerfile,添加内容
1 | vim Dockerfile |
创建locations.ini配置文件,添加内容
1 | vim locations.ini |
创建自定义server镜像
1 | docker build -t wpt-mac-server . |
创建agent目录
1 | mkdir wpt-mac-agent |
创建Dockerfile,添加内容
1 | vim Dockerfile |
创建script.sh, 添加内容
1 | vim script.sh |
修改script.sh权限
1 | chmod u+x script.sh |
创建自定义agent镜像
1 | docker build -t wpt-mac-agent . |
用新镜像运行实例 (注意先停掉之前运行的containers)
1 | docker ps 查看docker实例 |
m1平台构建有问题 应该是需要 设置–platform 暂时不会
打开调试工具 -> network 注意打钩选项 然后按住刷新,选择清空缓存并硬性重新加载
network底部有 transferred over network和 resources loaded by the page. 这两个大小有何区别?后边那个指的是解压后的大小,前边那个指的是源文件
下面重点研究瀑布图
瀑布图由长短不一的条状图构成,处于同一竖线起点的请求,就是并行请求,并行请求数量浏览器有上限,其他的请求必须等上一个请求完成后,才可以发出,瀑布图上可以看到
瀑布图上蓝色竖线表示dom加载完成的时间,红色表示所有资源加载完成的时间。
把鼠标放在到瀑布图上,还可以展示具体的时间构成
TTFB(Time To First Byte)
可以把结果保存至本地
主要看两个属性
command
+shift
+p
输入frame 选择展示帧数
转载于知乎
说起鉴权大家应该都很熟悉,不过作为前端开发来讲,鉴权的流程大头都在后端小哥那边,本文的目的就是为了让大家了解一下常见的鉴权的方式和原理。
认知:HTTP 是一个无状态协议,所以客户端每次发出请求时,下一次请求无法得知上一次请求所包含的状态数据。
HTTP 提供一个用于权限控制和认证的通用框架。最常用的HTTP认证方案是HTTP Basic Authentication
1 | // Authorization 加密过程 |
通用 HTTP 身份验证框架有多个验证方案使用。不同的验证方案会在安全强度上有所不同。
IANA 维护了一系列的验证方案,除此之外还有其他类型的验证方案由虚拟主机服务提供,例如 Amazon AWS ,常见的验证方案包括:
最常用的 Session 存储方式是 KV 存储,如Redis,在分布式、API 支持、性能方面都是比较好的,除此之外还有 mysql、file 存储。
如果服务是分布式的,使用 file 存储,多个服务间存在同步 session 的问题;高并发情况下错误读写锁的控制。
我们上面提到的流程中,缺少 Session 的刷新的环节,我们不能在用户登录之后经过一个 expires 时间就把用户踢出去,如果在 Session 有效期间用户一直在操作,这时候 expires 时间就应该刷新。
以 Koa 为例,刷新 Session 的机制也比较简单: 开发一个 middleware(默认情况下所有请求都会经过该 middleware),如果校验 Session 有效,就更新 Session 的 expires: 当前时间+过期时间。
优化:
有些情况下,只允许一个帐号在一个端下登录,如果换了一个端,需要把之前登录的端踢下线(默认情况下,同一个帐号可以在不同的端下同时登录的)。
这时候可以借助一个服务保存用户唯一标识和 sessionId 值的对应关系,如果同一个用户,但 sessionId 不一样,则不允许登录或者把之前的踢下线(删除旧 session )。
JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
JWT 由三部分组成,分别是 header(头部),payload(载荷),signature(签证) 这三部分以小数点连接起来。
例如使用名为 jwt-token 的cookie来存储 JWT 例如:
1 | jwt-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibHVzaGlqaWUiLCJpYXQiOjE1MzI1OTUyNTUsImV4cCI6MTUzMjU5NTI3MH0.WZ9_poToN9llFFUfkswcpTljRDjF4JfZcmqYS0JcKO8; |
使用.
分割值可以得到三部分组成元素,按照顺序分别为:
header
:
{"alg": "HS256", "type": "JWT"}
payload
:
1 | { |
signature
:
1 | const headerEncode = base64Encode(header); |
对于验证一个 JWT 是否有效也是比较简单的,服务端根据前面介绍的计算方法计算出 signature,和要校验的JWT中的 signature 部分进行对比就可以了,如果 signature 部分相等则是一个有效的 JWT。
为了减少 JWT Token 泄露风险,一般有效期会设置的比较短。 这样就会存在 JWT Token 过期的情况,我们不可能让用户频繁去登录获取新的 JWT Token。
解决方案:
可以同时生成 JWT Token 与 Refresh Token,其中 Refresh Roken 的有效时间长于 JWT Token,这样当 JWT Token 过期之后,使用 Refresh Token 获取新的 JWT Token 与 Refresh Token,其中 Refresh Token 只能使用一次。
OAuth 2.0 的四种方式 - 阮一峰的网络日志www.ruanyifeng.com
下面是转载,防止链接失效
OAuth 2.0 的标准是 RFC 6749 文件。该文件先解释了 OAuth 是什么。
OAuth 引入了一个授权层,用来分离两种不同的角色:客户端和资源所有者。……资源所有者同意以后,资源服务器可以向客户端颁发令牌。客户端通过令牌,去请求数据。
这段话的意思就是,OAuth 的核心就是向第三方应用颁发令牌。然后,RFC 6749 接着写道:
(由于互联网有多种场景,)本标准定义了获得令牌的四种授权方式(authorization grant )。
也就是说,OAuth 2.0 规定了四种获得令牌的流程。你可以选择最适合自己的那一种,向第三方应用颁发令牌。下面就是这四种授权方式。
注意,不管哪一种授权方式,第三方应用申请令牌之前,都必须先到系统备案,说明自己的身份,然后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)。这是为了防止令牌被滥用,没有备案过的第三方应用,是不会拿到令牌的。
授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。
这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。
第一步,A 网站提供一个链接,用户点击后就会跳转到 B 网站,授权用户数据给 A 网站使用。下面就是 A 网站跳转 B 网站的一个示意链接。
1 | https://b.com/oauth/authorize? |
上面 URL 中,response_type
参数表示要求返回授权码(code
),client_id
参数让 B 知道是谁在请求,redirect_uri
参数是 B 接受或拒绝请求后的跳转网址,scope
参数表示要求的授权范围(这里是只读)。
第二步,用户跳转后,B 网站会要求用户登录,然后询问是否同意给予 A 网站授权。用户表示同意,这时 B 网站就会跳回redirect_uri
参数指定的网址。跳转时,会传回一个授权码,就像下面这样。``
1 | https://a.com/callback?code=AUTHORIZATION_CODE |
上面 URL 中,code
参数就是授权码。
第三步,A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。
1 | https://b.com/oauth/token? |
上面 URL 中,client_id
参数和client_secret
参数用来让 B 确认 A 的身份(client_secret
参数是保密的,因此只能在后端发请求),grant_type
参数的值是AUTHORIZATION_CODE
,表示采用的授权方式是授权码,code
参数是上一步拿到的授权码,redirect_uri
参数是令牌颁发后的回调网址。
第四步,B 网站收到请求以后,就会颁发令牌。具体做法是向redirect_uri
指定的网址,发送一段 JSON 数据。
1 | { |
上面 JSON 数据中,access_token
字段就是令牌,A 网站在后端拿到了。
有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。RFC 6749 就规定了第二种方式,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)”隐藏式”(implicit)。
第一步,A 网站提供一个链接,要求用户跳转到 B 网站,授权用户数据给 A 网站使用。
1 | https://b.com/oauth/authorize? |
上面 URL 中,response_type
参数为token
,表示要求直接返回令牌。
第二步,用户跳转到 B 网站,登录后同意给予 A 网站授权。这时,B 网站就会跳回redirect_uri
参数指定的跳转网址,并且把令牌作为 URL 参数,传给 A 网站。
1 | https://a.com/callback#token=ACCESS_TOKEN |
上面 URL 中,token
参数就是令牌,A 网站因此直接在前端拿到令牌。
注意,令牌的位置是 URL 锚点(fragment),而不是查询字符串(querystring),这是因为 OAuth 2.0 允许跳转网址是 HTTP 协议,因此存在”中间人攻击”的风险,而浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险。
这种方式把令牌直接传给前端,是很不安全的。因此,只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间(session)有效,浏览器关掉,令牌就失效了。
如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为”密码式”(password)。
第一步,A 网站要求用户提供 B 网站的用户名和密码。拿到以后,A 就直接向 B 请求令牌。
1 | https://oauth.b.com/token? |
上面 URL 中,grant_type
参数是授权方式,这里的password
表示”密码式”,username
和password
是 B 的用户名和密码。
第二步,B 网站验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为 HTTP 回应,A 因此拿到令牌。
这种方式需要用户给出自己的用户名/密码,显然风险很大,因此只适用于其他授权方式都无法采用的情况,而且必须是用户高度信任的应用。
最后一种方式是凭证式(client credentials),适用于没有前端的命令行应用,即在命令行下请求令牌。
第一步,A 应用在命令行向 B 发出请求。
1 | https://oauth.b.com/token? |
上面 URL 中,grant_type
参数等于client_credentials
表示采用凭证式,client_id
和client_secret
用来让 B 确认 A 的身份。
第二步,B 网站验证通过以后,直接返回令牌。
这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。
A 网站拿到令牌以后,就可以向 B 网站的 API 请求数据了。
此时,每个发到 API 的请求,都必须带有令牌。具体做法是在请求的头信息,加上一个Authorization
字段,令牌就放在这个字段里面。
1 | curl -H "Authorization: Bearer ACCESS_TOKEN" \ |
上面命令中,ACCESS_TOKEN
就是拿到的令牌。
令牌的有效期到了,如果让用户重新走一遍上面的流程,再申请一个新的令牌,很可能体验不好,而且也没有必要。OAuth 2.0 允许用户自动更新令牌。
具体方法是,B 网站颁发令牌的时候,一次性颁发两个令牌,一个用于获取数据,另一个用于获取新的令牌(refresh token 字段)。令牌到期前,用户使用 refresh token 发一个请求,去更新令牌。
1 | https://b.com/oauth/token? |
上面 URL 中,grant_type
参数为refresh_token
表示要求更新令牌,client_id
参数和client_secret
参数用于确认身份,refresh_token
参数就是用于更新令牌的令牌。
B 网站验证通过以后,就会颁发新的令牌。
写到这里,颁发令牌的四种方式就介绍完了。下一篇文章会编写一个真实的 Demo,演示如何通过 OAuth 2.0 向 GitHub 的 API 申请令牌,然后再用令牌获取数据。
https://link.zhihu.com/?target=https%3A//blog.csdn.net/maxchenBug/article/details/88791514)
没有最好,只有最合适!!!
梳理总结:
适用场景
问题:
梳理总结:
使用场景:
梳理总结:
适用场景:
问题:
梳理总结:
适用场景:OAuth 分为下面四种模式
转载于知乎
延伸阅读
单点登录注销_Faker_Wang的博客-CSDN博客blog.csdn.net
[《手机扫码登录内网怎么实现的?》blog.csdn.net](
文档中的层叠上下文由满足以下任意一个条件的元素形成:
小总结
z-index相关:
详细介绍
<html>
);position
值为 absolute
(绝对定位)或 relative
(相对定位)且 z-index
值不为 auto
的元素;position
值为 fixed
(固定定位)或 sticky
(粘滞定位)的元素(沾滞定位适配所有移动设备上的浏览器,但老的桌面浏览器不支持);flex
) 容器的子元素,且 z-index
值不为 auto
;grid
) 容器的子元素,且 z-index
值不为 auto
;opacity
属性值小于 1
的元素(参见 the specification for opacity);mix-blend-mode
属性值不为 normal
的元素;none
的元素:
isolation
属性值为 isolate
的元素;will-change
值设定了任一属性而该属性在 non-initial 值时会创建层叠上下文的元素(参考这篇文章);contain
属性值为 layout
、paint
或包含它们其中之一的合成值(比如 contain: strict
、contain: content
)的元素。在层叠上下文中,子元素同样也按照上面解释的规则进行层叠。 重要的是,其子级层叠上下文的 z-index
值只在父级中才有意义。子级层叠上下文被自动视为父级层叠上下文的一个独立单元。总结:
Tips: 层叠上下文顺序
块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。
下列方式会创建块格式化上下文:
<html>)
float
不是 none
)position
为 absolute
或 fixed
)display
为 inline-block
)display
为 table-cell
,HTML表格单元格默认为该值)display
为 table-caption
,HTML表格标题默认为该值)display
为 table、``table-row
、 table-row-group、``table-header-group、``table-footer-group
(分别是HTML table、row、tbody、thead、tfoot 的默认属性)或 inline-table
)overflow
计算值(Computed)不为 visible
的块元素display
值为 flow-root
的元素contain
值为 layout
、content
或 paint 的元素display
为 flex
或 inline-flex
元素的直接子元素)display
为 grid
或 inline-grid
元素的直接子元素)column-count
或 column-width
(en-US) 不为 auto,包括 ``column-count
为 1
)column-span
为 all
的元素始终会创建一个新的BFC,即使该元素没有包裹在一个多列容器中(标准变更,Chrome bug)。块格式化上下文包含创建它的元素内部的所有内容.
块格式化上下文对浮动定位(参见 float
)与清除浮动(参见 clear
)都很重要。浮动定位和清除浮动时只会应用于同一个BFC内的元素。浮动不会影响其它BFC中元素的布局,而清除浮动只能清除同一BFC中在它前面的元素的浮动。外边距折叠(Margin collapsing)也只会发生在属于同一BFC的块级元素之间。
几个重要的应用:
BFC 可以包含浮动的元素(清除浮动,防止高度塌陷)
同一个 BFC 下外边距会发生折叠
BFC 可以阻止元素被浮动元素覆盖(左侧固定,右侧自适应布局)
可以参考知乎
在linux服务器中,新建/home/redistest/docker-compose.yml
,并书写以下内容
1 | version: "3" |
然后在当前目录运行docker-compose up -d
会自动抓取redis 并运行在15001端口
然后运行linux端口放行firewall-cmd --zone=public --add-port=15001/tcp --permanent
docker exec -it redis-test /bin/bash
想从镜像终端中出来,输入exit
ping ,如果运行正确 会返回pong
quit 断开当前redis 服务
auth 123456 // 登陆
select number 切换自动数据库,默认有0 - 15
设置数据
设置过期时间
Hash
hset obj key value
就像给一个对象设置键值对一样
hset brian name "brian"
hset brian age 19
brian = {
name: "brian",
age: 20
}
1
2
3
4
5
6
7
8
9
- hgetall obj 返回对象的key value对
- ```
hgetall brian
name
brian
age
19
Hmset 设置多对键值对
hmset brian name xxx age 19 email ueih@122
1
2
3
4
5
6
7
- Hmget 获取多个键值
- ```
hmget brian name age
xxx
19
list list操作
pub/sub 发布订阅
server命令
slowlog slow log是用来记录执行时间的日子系统
save 命令备份(同步任务,会阻塞,使用bgsave) 会生成一个dump.rdb,quit停止服务
CONFIG get dir 找到数据存在位置,把dump.rdb放入,重启服务就可以了
安装一个破解版的redis desktop manage,可以修改语言为中文,通过gui中的终端服务,可以很轻松的使用
首先安装redis npm install redis --save
redis配置示例如下
1 | import redis from "redis" |
测试
1 | setValue("ceshi", 122333) |
get 、set方法生产模式再次封装一下
1 | / set方法 |
1 | var mongoose = require('mongoose'); |
一般会把mongoose初始化,Schema,和操作表分离
1 | DBHelper.js |
1 | model/User.js // 对应数据库 users表 |
1 | // 模拟 |
添加 Model
的静态方法也十分简单,继续用 animalSchema
举例:
1 | // assign a function to the "statics" object of our animalSchema |
同样不要在静态方法中使用 ES6 箭头函数
js常用前两种原则,语言特性和后三种原则关联不大。
为何使用面向对象
1 | class jQuery { |
1 | class Vnode(tag, attrs, children) { |
js利用闭包和立即执行函数实现
1 | class SingleObj{ |
解决新旧代码不兼容的问题,尽量避免全局替换
1 | // 自己封装的ajax,使用方式如下 |
1 | <div id="example"> |
1 | @testable |
上面代码中,@testable
就是一个装饰器。它修改了MyTestableClass
这个类的行为,为它加上了静态属性isTestable
。testable
函数的参数target
是MyTestableClass
类本身。
基本上,装饰器的行为就是下面这样。
1 | @decorator |
也就是说,装饰器是一个对类进行处理的函数。装饰器函数的第一个参数,就是所要装饰的目标类。
装饰器实现 mixin
功能演示
1 | function mixins(...list) { |
第三方类库,提供了一些常用装饰器
npm地址
只读
1 | import { readonly } from 'core-decorators'; |
即将废弃
1 | import { deprecate } from 'core-decorators'; |
1 | class Circle{ |
例子1
1 | function readonly(target, name, descriptor) { |
例子2 函数改造,重点在于 call 和 this 的用法
1 | function log(target, name, descriptor){ |
代理类和目标类分离,隔离开目标类和使用者
常用场景
1 | // 本体 |
使用场景
前端最常用、最重要的模式
代码示意
1 | class Subject { |
应用场景
使用场景
1 | class Interator{ |
实例
使用场景
实际应用
不常用,暂时略过