blog's People
blog's Issues
把树结构转成数组,保持顺序。例如把多级左导航列表形式展示
import {reverse} from 'lodash'
treeToArray(tree) {
const stack = reverse(tree);
const array = [];
while (stack.length !== 0) {
const node = stack.pop();
node.level = node.level || 0;
if (node.children?.length) {
reverse(node.children).forEach(i => {
stack.push({ ...i, level: node.level + 1 });
});
}
array.push(node);
}
return array;
}
oauth2, oidc, ladp idp, 单点登录
最近被(oauth2, oidc, ladp idp, 单点登录)这几个概念搞得有点晕。研究下,做个整理
oauth2
OAuth2 是一种身份验证协议,用于进行身份验证和授权用户在应用程序中使用另一个服务提供者。
在 oauth 的流程中主要存在三个角色
- client (就是电脑面前的你)
- consumer (第三方应用)
- service provider (提供oauth服务的,比如 github)
没图说个毛。。。。先上个流程图
官方流程 这里咱就不啰嗦了。
oidc
openId connect 简单说就是对oauth2 的改善。在oauth2基础上多提供了 id_token
idp, ldap, 单点登录
idp 就是 identity provider 。而 ldap 个人理解就是 idp 的一种吧
最后单点登录,我理解的是对oauth2和oidc实现后的一种能力表现吧
浏览器缓存机制以及简单实践
通常浏览器缓存策略分为两种:强缓存和协商缓存
1、基本原理
- 浏览器在加载资源时,根据请求头的expires和cache-control判断是否命中强缓存,是则直接从缓存读取资源,不会发请求到服务器。
- 如果没有命中强缓存,浏览器一定会发送一个请求到服务器,通过last-modified和etag验证资源是否命中协商缓存,如果命中,服务器会将这个请求返回,但是不会返回这个资源的数据,依然是从缓存中读取资源
- 如果前面两者都没有命中,直接从服务器加载资源
2、强缓存。cache-control 为🌰
对需要设置强缓存的资源的请求头(req.headers)设置 'cache-control: max-age=60*60'
3、协商缓存
1. 基本概念
当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304并且会显示一个Not Modified的字符串
协商缓存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对Header来管理的
2. 已Etag 作为实现
3. 效果如下图
- image.png 已经使用了缓存(from memory cache)不会在发请求
- test.js 的状态码为304 ,不会重新获取资源
PS
整体DEMO 位于
深入理解一下vue-router
路由模式
ps 当前源码commit
vue-router 提供了三种运行模式:
- hash: 使用 URL hash 值来作路由。默认模式。
- history: 依赖 HTML5 History API 和服务器配置。查看 HTML5 History 模式。
- abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。
官网的例子来看看vue-router 如何运作的
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<router-view></router-view>
<script>
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
</script>
</div>
class VueRouter
主要这里定义了 router 的各种熟悉。常见的如大家所知
//比如设置mode 为 'history' 默认情况为hash(本文所说的模式), 设置 routes熟悉
options: RouterOptions;
//vue-router 实现的三种模式
mode: string;
history: HashHistory | HTML5History | AbstractHistory;
// 匹配路由的matcher
matcher: Matcher;
fallback: boolean;
// 各种钩子方法
beforeHooks: Array<?NavigationGuard>;
resolveHooks: Array<?NavigationGuard>;
afterHooks: Array<?AfterNavigationHook>;
vue.install(VueRouter)
默认浏览器下会自动安装 router 地址
- 设置了 _route 响应式属性
- 使用两个组件为上面的
<router-link> 和 <router-view>
这两个组件的作用大家在使用时候相信已经知道了。接下来我们要说的是如何点击 使得 变化的 - 当我们点击时
const handler = e => {
if (guardEvent(e)) {
if (this.replace) {
router.replace(location)
} else {
router.push(location)
}
}
}
const on = { click: guardEvent }
if (Array.isArray(this.event)) {
this.event.forEach(e => { on[e] = handler })
} else {
on[this.event] = handler // this.event 默认为click
}
源码
会触发 router.push router就是
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
this.history.push(location, onComplete, onAbort)
}
源码
当前history 咱们是默认的hash 模式
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const { current: fromRoute } = this
this.transitionTo(location, route => {
pushHash(route.fullPath)
handleScroll(this.router, route, fromRoute, false)
onComplete && onComplete(route)
}, onAbort)
}
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const route = this.router.match(location, this.current)
this.confirmTransition(route, () => {
this.updateRoute(route)
onComplete && onComplete(route)
this.ensureURL()
// fire ready cbs once
if (!this.ready) {
this.ready = true
this.readyCbs.forEach(cb => { cb(route) })
}
}, err => {
if (onAbort) {
onAbort(err)
}
if (err && !this.ready) {
this.ready = true
this.readyErrorCbs.forEach(cb => { cb(err) })
}
})
}
源码
会走调到 this.updateRoute(route)
updateRoute (route: Route) {
const prev = this.current
this.current = route
this.cb && this.cb(route)
this.router.afterHooks.forEach(hook => {
hook && hook(route, prev)
})
}
其中将会调用 this.cb(route)
this.cb 是什么时候设置的呢。
history.listen(route => {
this.apps.forEach((app) => {
app._route = route
})
})
源码
会去设置 app._route, 我们知道 app._route 是响应式的。会触发 render 函数。从而触发 router-view 的render行数
最后回去创建comment
然后就是vue 的re-render 从而达到router 的效果
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.