热搜:前端 nest neovim nvim

一些可能有用的前端小知识

lxf2023-06-02 02:12:44

跨域问题

什么是浏览器同源策略

要了解跨域问题,我们要先了解一下浏览器的同源策略(same origin policy)

首先,我们需要定义,什么是源(origin)

所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

一些可能有用的前端小知识

浏览器的同源策略指的是:js脚本不能向与本地域名不同的域名发送请求。这一策略产生的初衷是为了保护用户浏览器的cookie等数据,如果没有严格的跨域限制,用户的cookie很容易被转发出去,进而产生密码泄露等问题

  1. 为什么cookie会与密码有关

目前登录采用的一种主流的鉴权方式就是jwt(json-web-token),后端通过token来进行登录的鉴权,而这个token则是储存在了浏览器的cookie中,那么只要攻击者获得了你的未过期的cookie,他就可以登录你的账号

  1. cookie是怎么被转发出去的

这涉及到了XSS攻击(cross site scripting),举例而言,由于html中的一些可能有用的前端小知识,等标签加载时是不受同源策略的限制的,那么攻击者可以通过输入<imgsrc=.attacker's%20api``./>来进行一次跨域访问,通过document.getCookie()来获取本地的cookie并发送出去

如何解决跨域问题

大家在开发过程中的主机域名大部分情况下都是与后端部署的服务器域名不一致的,这种情况下就会触发跨域限制,那么我们应该如何解决这个问题呢

CORS

这种方法要求后端对于访问的资源的Access-Control-Allow-Origin字段进行设置,就字面意义而言,就是设置允许访问这个资源的origin,前端可以把自己本机的域名告诉后端,让他设置这个域名可以访问服务器上的资源

反向代理

这种方法被提出来是因为服务器端的请求是没有跨域问题的,同源策略只在浏览器端生效,那么我们可以在原始服务器的基础上再配置一个代理服务器,开发时前端请求这个代理服务器,这个代理服务器再将接收到的请求转发给原始服务器

React%20hooks原理及实现

hooks相信大家已经很熟悉了,但是使用hooks时需要遵守以下规范

只在最顶层使用%20Hook

不要在循环,条件或嵌套函数中调用%20Hook%20%20确保总是在你的%20React%20函数的最顶层以及任何%20return%20之前调用他们。遵守这条规则,你就能确保%20Hook%20在每一次渲染中都按照同样的顺序被调用。

这是为什么呢,本节尝试通过说明react%20hooks是如何实现的来解释为什么使用hooks时需要遵守以上规则

首先我们提出以下几个问题

  1. 我们都知道纯函数是无状态的,react%20hooks的提出就是为了使得函数有状态,那么这个状态,也就是hooks被储存在了哪里
  2. 我们使用hooks常常会声明多个hook,那么这些hook是怎么进行顺序调用的(这个问题直接关联到了为什么我们不能在循环条件或嵌套函数中调用hook)
React%20fiber

要解释第一个问题,我们需要先来了解一下react%20fiber

Why%20fiber

我们都知道浏览器中的js是单线程的,但是随着单个DOM的尺寸越来越大,更新一个DOM所要的开销也越来越大,react%20fiber提出就是为了减小更新DOM的开销,在过去,react通过virtual%20dom进行dom的更新,虽然virtual%20dom成功的把更新一次dom的时间复杂度从O(n^3)降低到的了O(nlogn),但其本质上还是对整个dom进行了一次更新,那么我们有没有可能以更小的单元对于dom进行更新呢

React%20fiber允许你将工作分为多个块,并将渲染工作分为多个帧。它还增加了为每个工作单元定义优先级的能力,以及暂停、重复使用和中止工作的能力。fiber之于线程就相当于线程之于进程,是一个更小的工作单元

How%20it%20works

我们在这里不详细解释react%20fiber如何更新整个dom,我们只介绍在react%20hooks中,fiber起什么作用

每一个组件都对应一个fiberNode,我们把fiberNode的结构简化为如下所示:

type%20Fiber{
%20%20%20%20//%20...
%20%20%20%20//%20用来创建输出的状态
%20%20%20%20memoizedState:%20any,
%20%20%20%20//%20...
}

memoizedState是一个链表结构,当我们通过useState等hook声明一个新的hook函数时,memoizedState会自动新增一项

我们可以把memoizedState理解为当前组件中使用的所有hook链接得到的链表的链表头,由于链表头不能被修改,我们需要一个新的变量来完成链表的增减,这个变量被称为workInProgressHook

可视化的结果如下

react组件更新时hook的操作

在了解到react hook的储存数据结构后,下一个问题就是当组件更新时,hook会进行什么样的操作

直观的来看,当组件更新时,workInProgressHook被重新指向memoizedState,随着各种hook的声明,workInProgressHook依次递增(但是这个过程中第一次渲染生成的hook链没有变化)

这也解释了为什么我们不能在循环,条件或嵌套函数中调用 Hook,这是为了确保hook调用顺序的正确,因为一旦有一个hook函数第二次渲染时没有被执行,workInProgressHook就会错位,对应的执行的hook函数也会错位

总结

简单的来说,我们可以把hook理解为储存在了全局的变量,组件更新时不会影响这些全局变量,同时由于我们通过一个全局的index来访问对应的hook,我们需要确保组件更新前后的react hook声明顺序不变

下面是一个以数组实现的useState(react源代码显然不是这么实现的,但大致思路是一样的)

const globalState:any[] = [];
let cursor:number = 0;

function render() {
    cursor = 0;
    ReactDOM.render(<App/>,document.getElementById("root"));
}

function useState<T>(initialState:T):[T,(newState:T) => void] {
    const currenCursor = cursor;
    globalState[currenCursor] = globalState[currenCursor] || initialState; 
    
    function setState(newState:T) {
        globalState[currenCursor] = newState;
        render()
    }
    
    ++cursor;
    return [globalState[currenCursor],setState];
}
本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!