CZX前端秘籍1

server/2024/10/25 3:08:06/

盒模型

1 标准盒模型

box-sizing: content-box;

margin + border + padding + content

2 怪异(IE)盒模型

box-sizing: border-box;

margin + content(border + padding + content)

3 区别

计算宽高的时候,怪异盒模型会把边框的内边距计算进去。

CSS特性

1 继承性

父元素的字体大小,字体颜色,行高,display:none...也会出现在子元素上。

2 优先级

谁的权重高就显示谁的样式。

!important 内联 ID class 属性 伪类 元素 继承 默认(vue中有深度选择器 deep)

3 层叠性

多个CSS声明应用在同一个元素时,权重相加,决定最终样式。

4 css变量和函数

声明变量的时候,变量名前面要加两根连词线 --。使用变量用var()函数。

<style>
body{--foo:red;
}p{color: var(foo);
}
</style>

变量的继承(initial关键字)

<style>
body{--foo: red;
}p{--foo: initial;
}
</style>

js控制css变量(getPropertyValue、setProperty)

通过js的dom节点对象,可以获取和修改当前节点的css变量值。
获取css变量:getPropertyValue('--name')
设置css变量:setProperty('--name', value)

<div id="header">hello world</div><style>
#header {--bgColor: #ffffff;
}
</style><script>let dom = document.getElementById("header");// 获取css变量let color = dom.getPropertyValue("--bgColor").trim();// 设置css变量dom.setProperty("--bgColor", '#f34e25');
</script>

var变量函数

作用:引用自定义的变量值。
第一个参数:引用的变量名称,第二个参数:回退值,表示如果第一个参数未定义,
使用回退值代替。

body {// 定义变量bgColor--bgColor: #ffffff;// 背景色取变量--bgColor的值,如果未定义,则取redbackground-color: var(--bgColor, red);
}

calc 函数

主要通过简单的数学计算,进行一些单位的计算,表达式支持加、减、乘、除。

min和max函数

min(val1... valN):接受任意数量的参数,每个参数也可以是表达式。取出参数中最小的值。
max(val1...valN):同上,取最大的值。

5 sass变量和函数

使用变量 $

$aaa: 16px;
.fontSize {font-size: $aaa;
}

@extend 继承 

.success{color:green;
}
.msg{@extend .success;color: #555555;
}

@if

当 @if 的表达式返回值不是 false 或者 null 时,条件成立,输出 {} 内的代码:

p{$num : 3;@if $num == 1 {color:red;}@else{border:red;}
}

@for

指令可以在限制的范围内重复输出格式,每次按要求(变量的值)对输出结果做出变动。

@for $i from 1 through 3 {.item-#{$i} {width: 2em * $i;}
}
上面等于
.item-1 { width: 2em; }
.item-2 { width: 4em; }
.item-3 { width: 6em; }

隐藏元素的方法

display:none;元素在页面上消失,不占据空间

visibility:hidden; 让元素消失,占据空间位置,一种不可见的状态

opacity:0; 设置了元素的透明度为0,元素不可见,占据空间位置。父元素设置的透明度,子元素也就被设置了对应的透明度

position:absolute; 使用定位,让元素移到页面之外

元素、文档流、BFC

块元素:独占一行,自上而下排列

行内元素:只占自身大小,从左向右排列,超过换行。不支持 margin-top 和 margin-bottom

两者:水平内边距padding求和,垂直外边距margin重叠

文档流:文档流处在页面的最底层,我们所创建的页面默认都是处在文档流中。

块元素在文档流中的特点:独占一行,自上而下排列;宽度默认为父元素的100%;高度默认被内容撑开。

行内元素:只占自身大小,从左向右排列,超过换行;宽度和高度默认被内容撑开。

BFC(块级格式化上下文)Block Formatting Context

它是一块独立的渲染区域。不同的 BFC 区域,进行渲染时互不干扰

触发条件

根元素(html);float值非none;overflow值非visible;position值为absolute、fixed;display值为inline-block、flex、inline-flex...

元素开启BFC后特点

1.开启BFC的元素不会被浮动元素所覆盖

2.开启BFC的元素子元素和父元素外边距不会重叠

3.开启BFC的元素可以包含浮动的子元素(解决高度塌陷)

.clearfix::after{ content: ''; display: table; clear: both; }

BFC功能总结

1、可以利用BFC解决两个相邻元素的上下margin重叠问题;

2、可以利用BFC解决高度塌陷问题;

3、可以利用BFC实现多栏布局(两栏、三栏、圣杯、双飞翼等)

SVG

基于XML语法格式的图像格式,可缩放矢量图,其他图像是基于像素的,SVG是属于对图像形状的描述,本质是文本文件,体积小,并且不管放大多少倍都不会失真

1.SVG可直接插入页面中,成为DOM一部分,然后用JS或CSS进行操作

2.SVG可作为文件被引入 img src='pic.svg'

3.SVG可以转为base64引入页面

px、rpx、vw、vh、em、rem

px:绝对长度、固定单位,无法根据页面的大小而改变

rpx: 小程序独自有的

vw:viewpoint width,视窗宽度,1vw等于视窗宽度的1%。

vh:viewpoint height,视窗高度,1vh等于视窗高度的1%。

em和rem:相对长度,适用于响应式布局(em的大小相对于父元素大小而改变,rem的大小相对于根元素的大小而改变)

据不同屏幕的宽度,以相同的比例动态修改html的font-size适配,并将px替换成rem,它可以很好的根据根元素的字体大小来进行变化,从而达到各种屏幕基本一直的效果体验

使用 window.reload 和 window.resize 进行监控配置rem

window.onload = () => { document.documentElement.style.fontSize = window.innerWidth / 375 * 100 + 'px'; }window.onresize = () => { document.documentElement.style.fontSize = window.innerWidth / 375 * 100 + 'px'; }

响应式开发(移动端适配)

1、使用rem、em、vw、vh、百分比、flex、@media媒体查询等布局

2、监听是手机端打开还是PC端打开,配置两套路由或样式

3、监听页面窗口大小,配置多套样式

页面渲染过程

1 浏览器会获取HTML和CSS的资源,然后把HTML解析成DOM树

2 再把CSS解析成CSSOM

3 把DOM和CSSOM合并为渲染树

4 计算和布局、把渲染树的每个节点渲染到屏幕上(绘制)

DOM树是和HTML标签一一对应的,包括head和隐藏元素;渲染树是不包含head和隐藏元素,渲染树包含CSSOM

语义化的理解

1 正确的标签做正确的事,方便团队开发和维护,语义化更具可读性,遵循W3C标准的团队都遵循这个标准,可以减少差异化

2 在没有CSS样式情况下也能够让页面呈现出清晰的结构

3 有利于SEO和搜索引擎、有助于爬虫抓取更多的有效信息

Doctype是HTML5的文档声明,通过它可以告诉浏览器,使用哪一个HTML版本标准解析文档。在浏览器发展的过程中,HTML出现过很多版本,不同的版本之间格式书写上略有差异。
如果没有事先告诉浏览器,那么浏览器就不知道文档解析标准是什么?此时,大部分浏览器将开启最大兼容模式来解析网页,我们一般称为怪异模式,这不仅会降低解析效率,而且会在解析过程中产生一些难以预知的bug,所以文档声明是必须的。

严格模式:严格模式是 JavaScript 的一种运行模式,不仅适用于前端开发,也适用于后端和任何 JavaScript 环境中。它的主要目的是增强 JavaScript 引擎的错误检查,并且使一些不安全或不推荐使用的语法在运行时抛出错误,从而提高代码质量和安全性。
在浏览器中,开启严格模式的方法是在 JavaScript 文件或 <script> 标签中的代码开头加上 "use strict"; 或者 'use strict';。
特点: 禁止使用全局变量,必须显式声明变量。严格模式下的 this 是 undefined 而不是全局对象。
混杂模式:页面以宽松向下兼容的方式显示,模拟老式浏览器的行为。

重排重绘

重排(回流):布局引擎会根据所有的样式计算出盒模型在页面上的位置和大小,对DOM的大小、位置进行修改后,浏览器需要重新计算元素的这些几何属性,就叫重排。减少重排可以增强浏览器效率。

重绘:计算好盒模型的位置、大小和其他一些属性之后,浏览器就会根据每个盒模型的特性进行绘制,对DOM的样式进行修改,比如color、透明度和background-color,浏览器不需要重新计算几何属性的时候,直接绘制了该元素的新样式,那么这里就只触发了重绘

使用虚拟 DOM就减少了重排和重绘。

DocumentFragment

DocumentFragment 是一个轻量级的、无父节点的 DOM 的节点类型,它不包含在文档树中,因此对它的操作不会引起页面的重绘和重排。

使用 DocumentFragment 可以显著减少页面的回流和重绘次数,提高性能。

// 直接操作DOM
const container = document.getElementById('container');for (let i = 0; i < 1000; i++) {const div = document.createElement('div');div.textContent = `Item ${i}`;container.appendChild(div);
}
// 使用 DocumentFragment
const container = document.getElementById('container');
const fragment = document.createDocumentFragment();for (let i = 0; i < 1000; i++) {const div = document.createElement('div');div.textContent = `Item ${i}`;fragment.appendChild(div);
}container.appendChild(fragment);

元素水平垂直居中

定位 + margin、定位 + transform、flex布局、gird布局、table布局

左侧固定右侧自适应

flex布局(左侧宽度固定,右侧flex: 1)、gird布局、table布局

float(左侧宽度固定,左右各自浮动,父盒子清除浮动)

 过渡和自定义动画

过渡:CSS3中,我们为了添加某种效果可以从一种样式转变到另一个的时候,无需使用JavaScript。性能提升。

transition: width 2s ease 1s; transition 四个参数: 属性的名称、过渡效果花费的时间、过渡效果、何时开始。

动画:CSS3 可以创建动画,它可以取代许多网页动画图像、JavaScript 实现的效果。还有很多参数。

添加了 aaaClass 的盒子背景会从红色变成黄色,过程为5秒,5秒后又还原为红色

.aaaClass {animation: myfirst 5 s;
}
@keyframes myfirst {from {background: red;}to {background: yellow;}
}

 画布 canvas

提供作画能力,fillStyle 填充绘画的颜色、渐变;rect() 绘制矩形;fillText() 绘制文本;createImageData() 创建新的图片......

场景:海报分享、截取图片上传

如果需要动态创建图形和图像,用canvas。如果要高质量的图形和图像则用矢量图 svg (图标、logo)

// 获取要截图的盒子元素,假设它有一个唯一的 ID 为 "boxToCapture",盒子或图片可拖拽
const elementToCapture = document.getElementById('boxToCapture');
// 创建一个 Canvas 元素
const canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
const ctx = canvas.getContext('2d');
// 将盒子元素内容绘制到 Canvas 上
ctx.drawImage(elementToCapture, 0, 0, 200, 200);
// 将 Canvas 中的内容导出为 PNG 图片
const dataURL = canvas.toDataURL('image/png');
// dataURL 现在包含截图的图像数据,可以进行进一步处理,比如展示在页面上或者上传到服务器

JS三部分

1、ECMAScript:JS的核心内容,描述了语言的基础语法。

2、文档对象模型(DOM):DOM把整个HTML页面规划为元素构成的文档。DOM 文档对象模型,就是一个API,可以通过操作这些API在页面上进行绘制节点,设置节点的属性和内容。

例如:document.getElementById('app');document.createElement('hr');app.appendChild(hr);app.setAttribute('class', 'aaa');

3、浏览器对象模型(BOM):对浏览器窗口进行访问和操作。BOM 浏览器对象模型,可以用来操作浏览器的打开、关闭、重加载等。

例如:location 当前页面的地址;history 浏览器浏览过的历史;navigator 浏览器当前的用户设备信息(可以看到浏览器内核等等);window 浏览器的高度、宽度。浏览器的滚动和打印功能......

JS部分内置对象

String、Boolean、Number、Array、Object、Function、Math、Date、RegExp...

Math:abs() 函数返回绝对值 sqrt() 接受一个非负正数,返回平方根 max() 最大值 min() 最小值......

Data:new Data() 获取当前时间戳 getYear() 获取年份 ......

数组方法

1、改变原数组:push 最后面加一个、pop 最后面删一个、unshift 最前面加一个、shift 最前面删一个、sort 排序、splice 可以删除替换增加元素

2、不改变原数组:reverse 反转顺序、concat 合并数组、join 将元素拼接成字符串、isArray 判断一个值是否为数组、findIndex 返回满足指定条件的第一个元素的索引,如果没有找到则返回 -1。

map:创建一个新数组,其元素是原数组经过指定函数处理后的结果。

const numbers = [1, 2, 3, 4, 5];
const squares = numbers.map(num => num * num);
console.log(squares); // 输出: [1, 4, 9, 16, 25]

filter:创建一个新数组,其中包含原数组中满足指定条件的所有元素。

let arr = [1, 2, 3, 4, 5];
let evenNumbers = arr.filter(item => item % 2 === 0);
console.log(evenNumbers); // 输出 [2, 4]

every:判断数组中所有元素是否都满足指定条件,如果是则返回 true,否则返回 false。

let arr = [2, 4, 6, 8, 10];
let allEven = arr.every(item => item % 2 === 0);
console.log(allEven); // 输出 true

some:判断数组中是否存在满足指定条件的元素,如果有则返回 true,否则返回 false。

let arr = [1, 3, 5, 7, 8];
let hasEven = arr.some(item => item % 2 === 0);
console.log(hasEven); // 输出 true

reduce:将数组中的元素通过指定函数进行累积计算,返回一个最终的结果。

let arr = [1, 2, 3, 4, 5];
let sum = arr.reduce((acc, curr) => acc + curr, 0);
console.log(sum); // 输出 15

为什么调用接口时,用 push 而不用 concat?

因为 push 是改变原数组,而 concat 是生成新数组。

for 数组、forEach 数组、for of 数组、for in 数组和对象都能遍历

let arr = [ "a", "b", "c", "d", "e" ];
let obj = { a: 1, b: 2, c: 3 }
for(let i = 0; i < arr.length; i++){ console.log(i, arr[i]) // 下标 值
}
arr.forEach((item, index) => { console.log(item, index) // 值 下标
})
for(let i of arr){ console.log(i) //值
}
for(let i in arr){ console.log(i, arr[i]) // 下标 值
}
for(let i in obj){ console.log(i, obj[i]) // 键 值
}

for、forEach差别:forEach 无法使用 break、return、continue 进行中断操作或跳出循环。只能使用 try、catch 中断,抛出异常。for循环能控制起点,forEach 不能(必须从第一个开始)。运行速度:for > forEach

try {arr.forEach((item, index) => {if (item == 1) {throw new Error("打断施法")}})
} catch (e) {if (e.message !== "打断施法") {throw e}
}

forEach 和 map 的区别

1、forEach()方法没有返回值,会更改原数组。

2、map() 有返回值,返回一个新数组,不会改变原数组,map() 不会对空数组进行检测。

3、map 的速度大于 forEach()

find:用于找出第一个符合条件的数组成员,并且返回该数组元素,如果没有满足条件的数组元素该方法返回undefined。

let arr1 = [1, 2, 3, 4, 5]
let num1 = arr1.find(function(item) {return item > 1;
});
console.log(num1); //2

findIndex:用于找出第一个符合条件的数组成员的索引值,并且返回该数组元素的索引值。如果没有满足条件的数组元素该方法返回-1。

let arr2 = [1, 7, 9, 4, 5]
let num1 = arr2.findIndex(item => item > 9);
console.log(num1); //-1
let num2 = arr2.findIndex(item => item > 3);
console.log(num2); //2

includes:判断数组是否包含指定值—是全等判断,第一个值是包含的指定值,第二个值是指定值的索引。

let arr4 = [2, 3, 4, 7, 5]
let flag = arr4.includes(2);
console.log(flag); //true
let flag1 = arr4.includes(3, 1);
console.log(flag1); //true

字符串方法

charAt() 方法可返回指定位置的字符;

concat() 方法用于连接两个或多个字符串或数组;

indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。没有为 -1;

lastIndexOf() 方法可返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索;

replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。

slice、substr、substring截取字符串; split 分割成数组; trim 去空格; toLowerCase toUpperCase 转英文大小写

JS对数据类的四种检测方式

typeof() 可以判断除了null以外的基本数据类型,引用数据类型不管用,识别数组等均为 object

instanceof() 只能判断引用类型,不能判断基本数据类型

constructor 几乎可以判断所有。如果声明一个构造函数,并把它的原形指向Array,他就识别不出来了

Object.prototype.toString.call()

闭包

什么是闭包?函数嵌套函数,内层函数访问外层函数的变量。

特点:变量持久化,不会被垃圾回收机制回收;防止变量和参数被外部污染,变量只在闭包内部可访问。

缺点:闭包较多的时候,会消耗内存,导致页面的性能下降,在IE浏览器中才会导致内存泄漏。

解决:在不需要用的时候,设为 null(垃圾回收机制自动回收)。

使用场景:防抖,节流,函数嵌套函数避免全局污染的时候。

防抖和节流区别:操作时不执行,确定不操作了才执行;节流到了时间执行一次。

function makeCounter() {let count = 0;return function() {count++;console.log(count)}
}
const conter = makeCounter()
console.log(makeCounter) // 整体函数
console.log(makeCounter()) // 内部函数
conter() // 1 只执行了内部函数,所以 count 的值增加
conter() // 2 只执行了内部函数,所以 count 的值增加
conter() // 3 只执行了内部函数,所以 count 的值增加

setTimeout、setInterval、requestAnimationFrame

定时器(setTimeout 延时调用、setInterval 定时调用)和requestAnimationFrame定时器 实现的动画在某些低端机上会出现卡顿、抖动的现象,任务被放进了异步队列中,只有当主程上的任务执行完之后,才会去检查该队列里的任务是否需要执行,因此setTimeout的实际执行时间一般要比其设定的时间晚一些。

requestAnimationFrame H5新增 在下一次重绘之前会更新动画帧所调用的函数。在隐藏元素中和页面不激活的状态下,requestAnimationFrame 不进行工作,减少CPU、GPU、内存的使用量。

内存泄漏

JS里已经分配内存地址的对象,但是由于长时间没有释放或者没办法清除,造成长期占用内存的现象,会让内存资源大幅浪费,最终导致运行速度慢,甚至崩溃的情况。

垃圾回收机制:js具有的回收机制,将不再使用的变量和对象进行回收,进行空间的释放。

因素:1 意外的全局变量泄露 2 console.log 使用 3 闭包泄露,赋值给全局变量后,对函数的引用一直存在 4 dom 泄露,remove dom 节点之后,但是remove 的 dom 节点对子节点的引用一直存在 5 一些未清空的定时器 6 监听事件没被销毁

小技巧:把功能写在函数里面能解决大部分内存泄漏问题问题,还有记得用let 和 const 声明变量别用var了

基本数据类型(栈)和引用数据类型(堆)

基本数据类型:基本数据类型保存在栈内存当中,保存的就是一个具体的值。

String Number Boolean undefined null Symbol

引用数据类型:保存在堆内存当中,声明一个引用类型的变量,它保存的是引用类型数据的地址。假如声明两个引用类型同时指向了一个地址的时候,修改其中一个那么另外一个也会改变。

Object Function Array

undefined 和 null

undefined 表示一个变量自然的、最原始的状态值,而 null 则表示一个变量被人为的设置为空对象,而不是原始状态。当需要释放一个对象时,直接赋值为 null 即可。

两个表示 无 的值,一个null,一个undefined。undefined 表示无的原始值,转化为数字时为 NAN;null表示为无对象,转化为数字时为 0。

事件委托(事件代理)

利用事件冒泡的机制来实现,也就是说把子元素的事件绑定到了父元素的身上。

好处:提高性能,减少事件的绑定,也就减少了内存的占用。

如果子元素阻止了事件冒泡,那么委托也就不成立,阻止事件冒泡event.stopPropagation()

在 DOM 中,事件捕获发生在事件冒泡之前,并且是事件处理的第一个阶段。在这个阶段,事件从文档的根节点向下传播到达目标元素。调用 event.stopPropagation() 只能阻止事件在捕获阶段或冒泡阶段中的继续传播,但它不能阻止事件捕获阶段的执行。

要完全阻止事件捕获阶段的执行,可以考虑在捕获阶段的事件处理函数中使用 event.stopImmediatePropagation() 方法,它会立即阻止事件继续传播,包括捕获和冒泡阶段。

addEventListener('click', 函数, true/false)

默认是false(事件冒泡),true(事件捕获)

三个参数( 指定事件名 指定要事件触发时执行的函数 可选,默认false。布尔值,指定事件是否在捕获或冒泡阶段执行)

事件捕获速度高于事件冒泡

执行上下文类型(3种)
1 全局执行上下文:全局执行上下文是默认的、最外层的执行上下文。它在整个页面生存周期内存在,负责全局变量的声明和函数的执行。
var globalVar = "I am global"; // 全局变量
function globalFunction() {console.log("I am a global function");
}
globalFunction(); // 输出:I am a global function
2 函数执行上下文:每当调用一个函数时,都会创建一个新的函数执行上下文。函数执行上下文在函数执行结束后被销毁。
function example() {var localVar = "I am local"; // 局部变量console.log(localVar);
}
example(); // 输出:I am local
3 Eval执行上下文:eval函数执行的代码会在一个新的执行上下文中运行,被称为Eval执行上下文。但由于使用eval存在安全和性能问题,应尽量避免使用。
eval("var evalVar = 'I am from eval';");
console.log(evalVar); // 输出:I am from eval执行上下文的生命周期
执行上下文的生命周期包括两个阶段:创建阶段(Creation Phase)和执行阶段(Execution Phase)。
创建阶段:
1 创建变量对象(VO):根据上下文的类型创建一个空的变量对象。
2 建立作用域链:作用域链是一个指向父级作用域的链表,用于查找变量的值。
3 确定this指向:在全局上下文中,this指向全局对象(如window)。在函数上下文中,this的值取决于函数的调用方式。
4 初始化变量对象:将函数的参数、函数声明和变量添加到变量对象中。
执行阶段:
1 执行代码:按照代码的顺序执行,对变量赋值等操作。
2 访问变量:通过作用域链查找变量的值。
3 执行函数:在函数上下文中,执行函数体内的代码。
作用域:
1 全局作用域(Global Scope):
全局作用域是指在代码的任何地方都能访问到的变量和函数。在浏览器中,全局作用域是 window 对象。
2 函数作用域(Function Scope):
函数作用域是指在函数内部定义的变量和函数只在该函数内部可见。函数外部无法直接访问函数内部的变量或函数。
3 块级作用域(Block Scope)(ES6 引入):
块级作用域指由一对花括号 {} 定义的区域。在块级作用域中定义的变量只在该区域内部可见,常见于 if 语句、for 循环等。作用域链:
在查找变量时,JavaScript 引擎会从当前执行上下文的作用域开始查找,如果在当前作用域中找不到,就会向上一级执行上下文的作用域查找,直到找到该变量或到达全局作用域(最顶层的执行上下文)为止。这种链式查找的过程就是作用域链。
匿名函数可以作为只用一次,不需要在其他地方使用的回调函数。当处理函数在调用它们的程序内部被定义时,代码具有更好地自闭性和可读性,可以省去寻找该处理函数的函数体位置的麻烦。

原型链

当我们访问一个对象的属性或方法时,如果该对象本身没有该属性或方法,JavaScript 就会通过__proto__属性向上查找,直到找到对应的属性或方法,或者到达原型链的尽头 null。

原型链的顶端是 null,这表示原型链的终点。在 JavaScript 中,对象的原型链最终会追溯到 null。

实例对象的隐式原型__proto__全等于构造函数的原型prototype

for in可遍历原型链上扩展的属性,Object.keys() 只遍历自身属性

// 定义一个构造函数 Person
function Person(name) {this.name = name;
}
// 在 Person 的原型上定义一个方法 sayHello
Person.prototype.sayHello = function() {console.log("Hello, " + this.name);
};
// 创建一个 Person 的实例
var person = new Person("John");
// 实例对象的隐式原型__proto__全等于构造函数的原型prototype
console.log(person.__proto__ === Person.prototype); // 输出:true// for in可遍历原型链上扩展的属性,Object.keys() 只遍历自身属性
Object.prototype.say="123";
var person ={ age: 18 };
for (var key in person) {console.log(key, person[key]);
}
// age 18
// say 123
console.log(Object.keys(person));
// ["age"]

new操作

1、先创建一个空对象

2、把空对象和构造函数通过原型链进行链接

3、把构造函数的this绑定到新的空对象身上

4、返回结果 res,如果 返回结果res 是一个对象则返回 res,否则返回 obj

function _new(aFn, ...args) {let obj = {};obj.__proto__ = aFn.prototype;const res = aFn.apply(obj, args);// 返回结果 res,如果 res 是一个对象则返回 res,否则返回 objreturn res instanceof Object ? res : obj;
}

Js创建对象的3种方式和Js继承5种方式

// 1 对象字面量方式
var obj = {}; obj.name = "张三";// 2 工厂模式(利用函数创建对象)
function createFactory(name) {var obj = new Object;obj.name = name;return obj;
}
var obj = new createFactory("王五");// 3 构造函数模式
function Person(uname) {this.uname = uname
}
Person.prototype.sing = function(songName){console.log(this.uname+"会唱"+songName);
}
var person1 = new Person("刘德华");
person1.sing("有只小鸟掉下水")1. 原型链继承(子类原型 等于 new 父类)
优点:父类方法可以复用
缺点:父类中所有的引用类型(对象、数组)会被子类共享,更改一个子类的数据,其他数据会受到影响,一直变化。(基本数据类型不会);子类实例不能给父类构造函数传参。2. 构造函数继承(在子类里,将父类的构造函数的this指向子类里的this)
优点:父类的引用类型不会被子类共享,不会互相影响。
缺点:子类不能访问父类原型属性(Person.prototype)上的方法和参数3. 组合式继承(将1和2结合起来)
优点:父类可以复用;父类构造函数中的引用属性数据不会共享
缺点:会调用两次父类的构造函数,会有两份一样的属性和方法,影响性能。4. 寄生组合继承(目前最优的继承方案,创建第三个构造函数,将第三构造函数的原型和父类的构造函数连接,再将子类的原型等于 new 一个第三构造函数,再与2结合)5. ES6的class类继承 extends
class Student extends Person{}

this指向的问题

1 全局对象中的this指向(指向的是window)

2 全局作用域或者普通函数中的this(指向全局window)

3 匿名函数中的this(永远指向了window,匿名函数的执行环境具有全局性,因此this指向window)

4 new 关键词改变了this的指向(指向新的实例对象)

5 call,apply,bind(可以改变this指向,指向第一个参数,不是箭头函数)

6 this永远指向最后调用它的那个对象(在不是箭头函数的情况下,谁调用指向谁)

7 箭头函数中的this,它的指向在定义的时候就已经确定了。(箭头函数它没有this,看外层是否有函数,有就是外层函数的this,没有就是window,因为箭头函数没有自己的this,也无法用call等进行更改this指向)

call, apply 第二个参数是数组, bind 有返回值的

function fun() {console.log(this.name)
}
let name = "window name"
let cat = {name: "喵喵"
}
fun() // window name
// call 可以改变函数中的 this 指向
fun.call(cat) // 喵喵
let dog = {name: "旺财",sayName() {console.log("我是" + this.name)},eat(foot1, foot2) {console.log("我喜欢吃" + foot1 + foot2)}
}
dog.sayName() // 我是旺财
dog.sayName.call(cat) // 我是喵喵
dog.eat("骨头", "饲料") // 我喜欢吃骨头饲料
dog.eat.call(cat, "鱼", "饼干") // 我喜欢吃鱼饼干
dog.eat.apply(cat, ["鱼", "饼干"]) // 我喜欢吃鱼饼干
let aaa = dog.eat.bind(cat, "鱼", "饼干")
aaa() // 我喜欢吃鱼饼干

事件循环(EventLoop)

JS是一个单线程的脚本语言,执行栈、宿主环境、任务队列、同步、异步(微任务、宏任务【定时器、点击事件】)

先同后异,先微后宏,先进先出。同步任务放在执行栈优先执行,异步任务放在宿主环境等待。异步任务的时间到了,或被触发(类似点击事件等),将异步任务推送到任务队列。

当执行栈执行完,执行栈就回去执行任务队列里面的任务。

promise 是同步任务,直接执行里面的代码,.then 才是异步任务,resolve 是调用成功,把值传递到 .then 里面。.then 是微任务

DOM 操作在原生JS中是同步操作,在VUE中是异步操作(在 Vue.js 中,DOM 操作本身并不是异步的。就像在原生 JavaScript 中一样,直接的 DOM 操作(例如通过 ref 或 this.$refs 访问元素并修改其属性)是同步执行的。但是,Vue.js 的响应式系统和虚拟 DOM 机制确实会引入一些异步的特性.this.$nextTick 可以确保回调函数在 DOM 更新完成后执行,用于获取更新后的 DOM 状态或执行其他操作)。

浏览器的存储方式

1 Cookies

优点: Cookies 是最早引入的本地存储技术,具有广泛的浏览器兼容性,并支持跨域存储。Cookies可以存储较小的数据量(通常限制为4KB),可以设置过期时间,支持持久化保存和定时清除。

缺点:Cookies 在每个 HTTP 请求中都会被发送到服务器端,造成额外的网络流量。受到浏览器限制,每个域名下的 Cookies 数量和总大小都有限制。同时,Cookies 中的数据可以被读取和算改,安全性有限。

2 Web Storage (Localstorage 和 SessionStorage)

Localstorage 本地存储(永久存在) SessionStorage 会话存储(页面关闭就没了,多个页面不共享)

优点: web storage 提供了更大的存储容量(通常限制为5MB) 且只在客户端存储,不会在每个请求中发送到服务器。Localstorage 和 SessionStorage 提供简单的键值对存储,并且在同一浏览器窗口下共享数据。

缺点: Localstorage 在浏览器中是永久性的,除非手动删除,否则数据会一直保留。由于浏览器限制,数据在不同的浏览器窗口和标签页之间无法共享。同时,对于较旧的浏览器版本,对 Webstorage 的支持可能不完整。

3 IndexedDB

IndexedDB 是一种通用的浏览器本地微型数据库,它不依赖于特定的应用或服务,而是作为现代 Web 应用程序的一部分,提供了一种持久化存储数据的机制。

Token

登录流程

1 客户端用账号密码请求登录

2 服务端收到请求后,需要去验证账号密码

3 验证成功之后,服务端会签发一个token,把这个token发送给客户端

4 客户端收到token后保存起来,可以放在cookie也可以是localstorage

5 客户端每次向服务端发送请求资源的时候,都需要携带这个token

6 服务端收到请求,接着去验证客户端里的token,验证成功才会返回客户端请求的数据

存储位置

localStorage的数据会在浏览器关闭后仍然存在,因此可以保持用户的登录状态。同时,localStorage中的数据可以在同一浏览器的所有标签页和窗口中共享。然而, localStorage中的数据可能会受到XSS(跨站脚本)攻击,因此需要对数据进行适当的编码和验证。

sessionStorage中的数据只在当前会话中存在,当用户关闭浏览器后,sessionStorage中的数据将被清除。

无感登录和无感刷新

为了保证安全性,后端设置的Token不可能长期有效,过了一段时间Token就会失效。而发送网络请求的过程又是需要携带Token的, 一旦Token失效,用户就要重新登陆,这样用户可能需要频繁登录,体验不好。为了保证安全性,后端设置的Token不可能长期有效,过了一段时间Token就会失效。 而发送网络请求的过程又是需要携带Token的,一旦Token失效,用户就要重新登陆,这样用户可能需要频繁登录,体验不好。

方法一:调用定时器,定时刷新,浪费性能。

为了解决这个问题,采取双Token(Access_Token,Refresh_Token)无感刷新,用户完全体会不到Token的变化,但实际上,Token已经刷新了。

方法二:双Token机制

Access_Token:用于鉴定用户身份,即每次发送网络请求都需要携带这个Access_Token。有效时间短。

Refresh_Token:用于刷新Access_Token,即调用A接口需要携带Refresh_Token, 用它换得最新的Access_Token。有效时间长。

流程

1.登录成功后保存token 和 refresh_token

2.在响应拦截器中对401状态码引入刷新token的api方法调用

3.替换保存本地新的token

4.把错误对象里的token替换

5.再次发送未完成的请求

6.如果refresh_token过期了,判断是否过期,过期了就清楚所有token重新登录

应用场景 小程序,单点登录,移动应用或者是web网站应用当中,或者是第三方授权操作处理等

HTTP协议规定的协议头和请求

1 请求头信息

Accept:浏览器告诉服务器所支持的数据类型

Host:浏览器告诉服务器我想访问服务器的哪台主机;

Referer:浏览器告诉服务器我是从哪里来的(防盗链)

User-Agent:浏览器类型、版本信息

Date:浏览器告诉服务器我是什么时候访问的

Connection:连接方式

Cookie

X-Request-With:请求方式

2 响应头信息

Location:这个就是告诉浏览器你要去找谁

Server:告诉浏览器服务器的类型

Content-Type:告诉浏览器返回的数据类型

Refresh:控制了的定时刷新

常见的http状态码

200 请求成功,表示从客户端发送给服务器的请求被正常处理并返回。

204 表示客户端发送给服务端的请求得到了成功处理,但在返回的响应报文中不含实体的主体部分,即没有资源可以返回。

301 永久重定向,被请求的资源已永久移动到新位置(URL),之后应使用更改的URL。

302 临时重定向,请求的资源现在临时从不同的URLI响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。

400 表示前端请求报文中存在语法错误

401 访问者访问的页面未经授权

403 服务器拒绝该次访问

404 文件请求不到,当用户试图访问Web服务器(通常是一个网页)上某个实际不存在的资源时,就会发生404错误。无效链接

500 内部服务器错误,一般是服务器内部代码出现错误。

502 无效网关,作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。

503 表示服务器暂时处于超负载或正在进行停机维护,无法处理请求。

TCP连接建立时需要经过3次握手,断开时经过4次挥手。

HTTP协议作为应用层协议

http和https区别

1 https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

2 http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。

3 http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443

AJAX请求

1 在不重新加载整个网页的前提下,与服务器交换数据并更新部分内容

过XmlHttpRequest对象向服务器发送异步请求,然后从服务器拿到数据,最后通过JS操作DOM更新页面

2 get和post区别

get 通过 地址栏 url 传输,可见,数据量小,相对不安全,当回退再次进入页面时,不清除数据,不重复调用接口,有缓存

post 通过 body 传输,可见可不见,数据量大

3 浏览器的缓存策略

本地缓存(强缓存)不发起请求,直接使用缓存里的内容,浏览器把JS,CSS,image等存到内存中,下次用户访问直接从内存中取,提高性能

协商缓存(弱缓存)需要像后台发请求,通过判断来决定是否使用协商缓存,如果请求内容没有变化,则返回304,浏览器就用缓存里的内容

4 同源策略是浏览器的安全策略

http:// www. aaa.com:8080/index/vue.js

协议 子域名 主域名 端口号 资源

同源策略是浏览器的核心,如果没有这个策略就会遭受网络攻击

主要指的就是协议 + 域名(子 + 主) + 端口号三者一致,若其中一个不一样则不是同源,会产生跨域

三个允许跨域加载资源的标签:img link script

跨域是可以发送请求,后端也会正常返回结果,只不过这个结果被浏览器拦截了!

解决方法:JSONP;CORS;websocket;反向代理(proxy)

文件上传

分片上传(Chunked Upload)

1 选择文件:使用 input type='file' 或者Vue组件库中的文件选择组件,让用户选择要上传的文件。

2 文件分片:当用户选择文件后,首先需要对文件进行分片处理。分片的大小可以根据实际需求设定,通常在1MB到10MB之间。分片可以使用File API中的File.slice()方法进行分割,并依次上传到服务器

3 上传片段:上传时需要注意为每个分片添加必要的标识(如文件名、片段序号等)以及处理进度条显示

4 完成上传:当所有分片上传完成后,调用接口,通知服务器进行合并操作,确保文件完整性

断点续传

1 保存上传状态:在前端,需要保存每个块的上传状态,以便在上传中断时能够恢复。可以使用本地存储(如localStorage)来保存已上传块的信息,例如上传进度、已上传块的索引等。

2 恢复上传:如果上传中断,用户可以在适当的时机重新加载页面或重新访问上传页面。此时,前端可以从保存的状态中获取已上传的块信息,并从中断处继续上传。

秒传(快传)

1 在Vue.js前端,实现秒传功能的关键在于在文件上传前计算文件的哈希值,并将该哈希值与后端进行比对。如果后端返回文件已存在的信息,即可视作秒传成功。

2 在前端使用浏览器的File API计算文件的哈希值,一般使用MD5算法。可以使用第三方库如spark-md5来简化哈希计算过程。

3 在上传文件之前,先计算文件的哈希值,并将该值与服务器进行比对。如果服务器返回文件已存在的信息,则可以停止上传。

并发多文件上传

1 选择文件:允许用户选择多个文件,并将这些文件存储在一个数组或者列表中,准备进行并发上传。

2 并发上传:使用Promise.all或其他并发控制机制,同时上传多个文件。在Vue组件中,可以使用Array.map方法创建一个上传每个文件的Promise数组,并使用Promise.all来等待所有文件上传完成。

3 上传进度:可以实现上传进度条或者上传进度显示,以提升用户体验。通常在每个文件上传的过程中更新进度条

进度条显示和用户体验、错误处理和安全性

进度条、全部传输完成进行弹出提示、网络错误时,重新连接或者提示

对文件大小格式等进行限制

JSON

JSON是一种纯字符串形式的数据,它本身不提供任何方法,适合在网络中进行传输。

可以把JSON数据以字符串的形式保存在数据库,缓存中。提供了JSON.parse() JSON.stringify()

Git 操作

配置 .gitignore 文件

.DS_Store
node_modules/
dist/
package-lock.json
tests/**/coverage/# Editor directories and files
.idea
.vscode

git clone 克隆项目、git branch -a 查看项目的所有分支、git status 查看状态、git add . 添加全部

git reset HEAD^hello.php 回退 hello.php 版本、git commit -m '内容'、git pull 下拉、git push 推

JS的延迟加载方式

script标签的 defer 属性,立即下载,但是延迟执行

setTimeout 操作dom,动态创建 script 标签

把 script 放在最后

普通<script>标签:同步加载,立即阻塞HTML解析,加载完成后,继续解析HTML。

defer脚本:异步加载,不阻塞 HTML 解析,等 HTML 全部解析完后按顺序执行。

async脚本:异步加载,不阻塞 HTML 解析,那个先加载完就立即执行那个,无序。

script、script async 和 script defer 的区别
1 <script> 标签
普通的 <script> 标签用于引入 JavaScript 文件或内嵌 JavaScript 代码。它的特点是在浏览器遇到 <script> 标签时,会立即下载并执行其中的代码,然后再继续解析 HTML 文档。
2 <script async>
async 属性用于异步加载 JavaScript 文件。异步加载的脚本不会阻止 HTML 解析,而是在加载完成后立即执行,同时继续解析 HTML。
3 <script defer>
defer 属性也用于延迟加载 JavaScript 文件,但是与 async 不同的是,defer 保证脚本的执行顺序与它们在文档中的顺序一致。

阻塞 HTML 解析:普通 <script> 会阻塞 HTML 解析,async 和 defer 不会。

深浅拷贝

浅拷贝是创建一个新的对象或数组,并将原始数据的值复制到新对象中。当原始数据是基本数据类型(如数字、字符串、布尔值)时,浅拷贝会直接复制其值。然而,当原始数据是引用类型(如对象或数组)时,浅拷贝只会复制引用,而不是创建新的独立副本。这意味着新对象和原始对象会共享同一份数据,对其中一个对象的修改会影响到另一个对象。

深拷贝是创建一个全新的对象或数组,并递归地复制原始数据中的所有值和嵌套对象。深拷贝会创建独立的副本,使得新对象和原始对象完全独立,互不影响。

直接赋值 浅拷贝

使用...扩展运算符、一层深拷贝,多层浅拷贝

Object.assign() 主要用于对象合并,将源对象中的属性复制到目标对象中,他将返回目标对象。一层深拷贝,多层浅拷贝

JSON.parse(JSON.stringify()) 深拷贝,但是无法拷贝对象方法

双for循环实现深拷贝函数

let const var

let 和 const 存在块级作用域,var 不存在;

var 存在变量提升,let 和 const 不存在, 即只能在声明后使用, 否则报错;

var 定义的变量可以重复声明,let 和 const 不行。

var 在全局声明的变量为全局变量, 并将该变量添加为全局对象的属性(在浏览器环境下是window对象,在Node.js环境下是global对象)。let 和 const 不会;

var a = 2
let b = 3
console.log(a) // 2
console.log(this.a) // 2
console.log(b) // 3
console.log(this.b) // undefined

解构赋值、模板字符串、三点运算符、形参默认值

let username = obj.username; let age = obj.age; ==> let { username, age } = obj;

模板字符串必须用 `` 包含, 动态部分使用 $ {} 拼接

let arr1 = [1, 3, 5]; ===> let arr2 = [2, ...arr1, 6];

箭头函数

当箭头函数只有一句时, 不需要用括号包围; 箭头函数没有自己的this,( 普通函数谁调用, 指向谁, 直接使用默认为window调用), 箭头函数指向父级上一层, 无法改变 this 指向

let obj = {afn: function() {console.log(this, "afn")},bfn: () => {console.log(this, "bfn")}
}
obj.afn() // obj
obj.bfn() // window

1 箭头函数只有一句时候可以省略return,参数只有一个时,可以省略()。 

2 没有自己的this

3 没有arguments对象

promise、 async、 await

回调地域问题

// 要先拿到汉堡,再拿可乐,只能将可乐写在汉堡里面,这就是回调地域
setTimeout(() => {console.log("汉堡")setTimeout(() => {console.log("可乐")}, 1000)
}, 2000)

promise 可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数, 把异步操作队列化, 解决“ 回调地域”。promise是同步任务,.then才是异步任务。

三种状态: pending 初始状态, fulfilled 操作成功, rejected 操作失败

let hb = function() {return new Promise(function(resolve, reject) {setTimeout(() => {resolve("汉堡01")}, 2000)})
}
let kl = function() {return new Promise(function(resolve, reject) {setTimeout(() => {resolve("可乐01")}, 1000)})
}
// 先拿到汉堡 再拿到可乐 链式代码
hb().then((res) => {console.log(res)return kl()
}).then((res) => {console.log(res)
})

async await 同步代码做异步的操作, 两者必须搭配使用、 async表明函数内有异步操作, 调用函数会返回promise。

await后的promise如果是reject状态, 那么整个async函数都会中断, 后面的代码不执行

// async awit
let afn = async () => {console.log(await hb())console.log(await kl())
}
afn()

async await 的返回

1 函数前面加上 await 关键字,则该函数会返回一个结果为 promise 的对象。

2 await 是在等一个表达式的结果,等一个返回值(回调成功的内容)

3 如果 await 右侧是一个 promise 对象,则 await 返回的是 promise 成功的值。

注意:1.await 必须写在 async 函数中,但 async 函数中可以没有 await。

注意:2.如果 await 的 promise 失败了,就会抛出异常,该异常需要通过 try catch 捕获处理。

generator

新增了generator *函数, 解决异步编程的一种方案

let fn = function*() {yield "a"yield "b"yield "c"
}
let f = fn();
console.log(f.next()) // {value: "a", done: false}
console.log(f.next()) // {value: "b", done: false}
console.log(f.next()) // {value: "c", done: false}
console.log(f.next()) // {value: undefined, done: true}

基本数据类型( Symbol)

用法: 定义对象唯一的属性名。

特点: 1 Symbol 属性对应的值唯一, 解决命名冲突问题。 2 Symbol 的值不能与其他数据进行计算, 包括字符串拼接。 3 for in、for of 遍历时, 不会遍历 Symbol 属性。

						
let sy = Symbol("key01");
let syObj = {};
syObj[sy] = "kk";
console.log(syObj); // { syObj(key01): "kk" }

set集合 和 map集合

// set集合用于存放不重复的数据
// add(数据): 添加一个数据到set集合末尾, 如果数据已存在, 则不进行任何操作
// has(数据): 判断set中是否存在对应的数据, 返回true / false
// delete(数据): 删除匹配数据
// clear(): 清空整个set集合
// size: 获取set元素集合的元素数量( 只读, 不能赋值, 赋值无效)
const s1 = new Set()
s1.add(1)
s1.add(2)
s1.add(3)
s1.add(1) // 无效
console.log(s1) // Set(3) {1, 2, 3}
console.log(s1.has(4)) // false
s1.delete(2)
console.log(s1) // Set(2) {1, 3}
s1.clear()
console.log(s1) // Set(0)
console.log(s1.size) // 0
// set的应用:求两个数组的并集、交集、差集,要求:不能出现重复项,得到的结果是一个新数组
const arr1 = [22, 33, 44, 55, 66, 77, 11, 22, 44]
const arr2 = [55, 88, 99, 656, 888, 44, 33, 11]
// 将数组转换为 Set,去除重复元素
const set1 = new Set(arr1);
const set2 = new Set(arr2);
// 并集 (两个数组的所有元素)
cosnt result = [...new Set(arr1.concat(arr2))]
// map集合 键值对数据集合的特点: 键不可重复, 专门用于存储多个键值对数据。( 在map出现之前使用对象存储键值对,但是有几个问题, 键名只能是字符串, 获取数据的数量不方便。)
const str = new Map([["a", 1],["b", 2],["c", 3]
])
console.log(str) // Map(3) {"a" => 1, "b" => 2, "c" => 3}
// size:只读属性,获取当前map中的键数量
console.log(str.size) // 3
// set(键,值):设置一个键值对,键和值可以是任何类型
// 如果键不存在,则添加一项
// 如果键已存在,则修改它的值
str.set("d", 4)
str.set("a", 11)
console.log(str) // Map(4) {"a" => 11, "b" => 2, "c" => 3, "d" => 4}
// get(键):根据一个键得到对应的值
console.log(str.get("a")) // 11
// has(键):判断某个键是否存在
console.log(str.has("a")) // true
// delete(键):删除指定的键
str.delete("a")
console.log(str) // Map(3) {"b" => 2, "c" => 3, "d" => 4}
// clear() :清空map
str.clear()
console.log(str) // Map(0) {}
str.set({name: "张三"
}, 4)
console.log(str) // Map(1) {{ name: "张三" } => 4}

迭代器( iterator)

拥有next 方法返回对象。 value 是当前迭代的值, 而 done 代表迭代是否完成。

可以迭代的对象, 是因为本身拥有 迭代器。

数组, set集合, Map集合 本身拥有迭代器可以直接for of对象不行。 需要自己添加迭代器。( 使用for in )

 新增了定义类的语法糖( class)

// es6 class
class Student {constructor(name) {this.name = name}say() {console.log("你好,我是" + this.name)}
}
let stu1 = new Student("stu1")
let stu2 = new Student("stu2")
stu1.say()
stu2.say()// 在class中, 可以使用static关键字定义静态方法。 
// 静态方法不需要实例化类就可以被调用,可以通过类名去访问属性和方法, 而实例对象访问不了。class ShuiGuo {static type = "西瓜";static eat = function() {console.log("水果真好吃!");}
}
let shuiguo = new ShuiGuo();
console.log(ShuiGuo.type); //西瓜
ShuiGuo.eat(); //水果真好吃!
console.log(shuiguo.type); //undefined
shuiguo.eat(); //Uncaught TypeError: shuiguo.eat is not a function// super关键字 作为函数使用
class Parent {constructor() {console.log("Parent constructor");}
}
class Child extends Parent {constructor() {super(); // 调用父类的构造函数console.log("Child constructor");}
}
const child = new Child(); // 输出 "Parent constructor" 和 "Child constructor"
// super关键字 作为对象使用
class Parent {constructor() {this.name = "Parent";}sayHello() {console.log("Hello from " + this.name);}
}
class Child extends Parent {constructor() {super(); // 调用父类的构造函数this.name = "Child";}sayHello() {super.sayHello(); // 调用父类的sayHello方法console.log("Extra greeting from " + this.name);}
}
const child = new Child();
child.sayHello(); // 输出 "Hello from Child" 和 "Extra greeting from Child"

新增了 import 和 export 语句, 用于模块化导入和导出

1 CommonJS 模块的require是同步加载模块,ES6 模块的import命令是异步加载

2 require 运行时加载,可以在代码的任何地方使用。import 编译时加载,必须放在文件开头。

3 require导入整个模块支持解构赋值。import 可以选择性地导入模块中的特定部分。

4 require导入的值被修改时,源对象不会被改变,相当于深拷贝;import导入的对象值被改变时,源对象也会被改变,相当于浅拷贝。

webSocket

webSocket和http 一样都是基于TCP的可靠性传输协议,都是应用层协议。webSocket是双向传输,http只能单向传输

前端实现WebSocket心跳机制的方式主要有两种:1. 使用setInterval定时发送心跳包。2. 在前端监听到WebSocket的onclose()事件时,重新创建WebSocket连接

重连机制: 实现WebSocket的重连机制,当连接断开时,自动尝试重新连接服务器。

心跳机制: 定时向服务器发送心跳消息,以保持连接的活跃状态。如果长时间没有收到服务器的响应,可以视为连接断开,并进行重连操作。

断线提示: 当连接断开时,及时向用户提示网络异常,并提供重新连接的按钮或提示。

定时器心跳模式不准,处理方式

JavaScript单线程特性: JavaScript是单线程的,当浏览器执行其他耗时任务时,定时器可能无法准确按时触发。

使用requestAnimationFrame: 如果定时器主要用于动画或页面渲染方面的操作,可以考虑使用requestAnimationFrame API,它更加适合在每一帧绘制之前执行任务。

使用Date对象计算时间差: 可以通过Date对象获取当前时间,并计算与上一次定时器触发的时间差,以此来调整下一次定时器的触发时间,从而减小误差。

JS WebSocket 的断线处理方式和代码

1. 监听 onclose 事件

当 WebSocket 连接因为某些原因关闭时,onclose 事件会被触发。你可以在这个事件处理器中添加重新连接的逻辑。

let socket = new WebSocket('ws://yourserver.com/socket');socket.onclose = function(event) {console.log('Connection closed. Code:', event.code, 'Reason:', event.reason);// 尝试重新连接setTimeout(function() {connect();}, 5000); // 延迟5秒后重连
};function connect() {socket = new WebSocket('ws://yourserver.com/socket');socket.onopen = function() {console.log('Connected to the server.');};socket.onmessage = function(message) {console.log('Received:', message.data);};socket.onerror = function(error) {console.error('Error detected: ', error);};
}

2. 监听 onerror 事件

虽然 onerror 通常用于报告在建立连接过程中的错误,但也可以用来作为额外的断线检测手段。

socket.onerror = function(error) {console.error('WebSocket error observed:', error);// 可以在这里添加重新连接的逻辑
};

3. 心跳检测

为了确保连接的有效性,可以定期发送心跳消息给服务器。如果一段时间内没有收到服务器的响应,则认为连接已经断开,并尝试重新连接。

const HEARTBEAT_INTERVAL = 15000; // 每15秒发送一次心跳
let heartbeatInterval;function startHeartbeat() {heartbeatInterval = setInterval(() => {if (socket.readyState === WebSocket.OPEN) {socket.send(JSON.stringify({ type: "heartbeat" }));}}, HEARTBEAT_INTERVAL);
}function stopHeartbeat() {clearInterval(heartbeatInterval);
}socket.onopen = function() {console.log('Connected to the server.');startHeartbeat(); // 连接成功后开始心跳检测
};socket.onclose = function() {console.log('Connection closed.');stopHeartbeat(); // 断线后停止心跳检测// 重新连接逻辑...
};socket.onmessage = function(message) {const data = JSON.parse(message.data);if (data.type === "heartbeat") {console.log("Server heartbeat received");} else {console.log('Received:', message.data);}
};

4. 使用库

对于更复杂的应用场景,考虑使用成熟的 WebSocket 库,如 Socket.io 或者 SockJS,这些库内置了重连机制和心跳检测功能,能够更好地处理断线情况。

前端

postMessage 用法(可以给iframe传值,将message传递给指定窗口)

postMessage(data,origin)方法接受两个参数

// 发送消息
let iframeWindow = document.getElementById("myframe").contentWindow;
iframeWindow.postMessage("aaa", "http://www.wrox.com");
1. data:- 要传输的数据,推荐使用字符串格式,其他格式的浏览器的兼容性不好- 如果要传输结构化数据,可以通过JSON.stringify处理,接收时用JSON.parse转换回来
2. origin:- 指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写- 如果不想限制接收目标源:可以传 "*"- 如果目标与当前窗口同源:可以传 "/"
// 接收消息
window.addEventListener("message", (event) => {// 判断源路径是否来自预期发生者if (event.origin.includes("http://www.wrox.com")) {// 获取传过来的数据console.log(event.data)// 再传回去一条消息event.source.postMessage("已收到消息", "p2p.wrox.com")}
})
// event 包含3个参数
- event.data: 接收到的数据
- event.origin: 发送消息的文档源
- event.source: 发生消息的文档中window对象的代理

乾坤

前端前端架构中,如果你使用了乾坤(Qiankun)作为主应用的基座,以及多个子应用,可以通过以下方式在基座和子应用之间传递数据:

1. 基座向子应用传值:

通过 props 传递: 如果你在使用乾坤时,将子应用视为组件加载,你可以通过 props 的方式将数据传递给子应用。在基座中的配置中,可以通过 props 传递数据给子应用。

通过自定义事件或消息总线: 在基座中使用自定义事件或消息总线(例如 Event Bus 或者 Pub/Sub模式)来发布事件,子应用在初始化时订阅这些事件,并在事件被触发时获取数据。

2. 子应用向基座传值:

通过事件通知基座: 子应用可以通过触发事件的方式来通知基座,基座监听这些事件并获取数据。使用乾坤提供的通信API: 乾坤提供了initGlobalState和onGlobalStateChange等方法,可以在基座中初始化一个全局状态,并监听全局状态的变化,子应用可以修改全局状态,从而实现基座与子应用之间的通信。

3. 子应用之间传值:

通过事件总线: 子应用之间可以使用事件总线或者状态管理库(如 Vuex、Redux 等)来共享数据,一个子应用发布事件,另一个子应用监听事件并获取数据。使用状态管理库: 如果子应用之间需要共享状态,可以使用状态管理库来管理共享状态,确保不同子应用之间的数据一致性。

总的来说,基座和子应用之间的数据传递可以通过 props、自定义事件、消息总线、乾坤提供的通信API等方式实现,具体方法取决于你的应用场景和需求

使用微前端(qiankun),解决样式污染问题

方案一:使用插件转换子应用class的前缀名称,尽量不和主应用重名(不推荐)

change-prefix-loader或者postcss-change-css-prefix

方案二:使用qiankun自带的沙箱隔离(不推荐)

start({sandbox: {// 开启严格的样式隔离模式。这种模式下 qiankun 会为每个微应用的容器包裹上一个 [shadow dom]节点,从而确保微应用的样式不会对全局造成影响。strictStyleIsolation: true,// 设置实验性的样式隔离特性,即在子应用下面的样式都会包一个特殊的选择器规则来限定其影响范围experimentalStyleIsolation: true}
})

使用qiankun自带的沙箱隔离,在主应用中start函数中,通过配置sandbox做到样式隔离。但这样直接使用沙箱隔离会遇到很多坑。

坑:当启用strictStyleIsolation时,因为某些UI框架(例如element、ant-design等)可能会生成一些弹出框直接挂载到主应用的document.body下,此时由于脱离了shadow tree。会导致页面报错。

浏览器乱码原因是什么?如何解决?

服务器在发送响应头时指定了错误的字符编码,或者没有指定字符编码。

解决:确保服务器在发送响应头时正确设置了 Content-Type,包含正确的字符编码信息。例如:

HTML文档中没有使用 <meta charset="UTF-8"> 或者使用了错误的字符编码声明。

nginx、数据库配置 utf-8

懒加载和预加载

懒加载是指延迟加载页面上的某些资源,直到它们真正需要时才进行加载。通常用于图片、视频或其他非关键资源,以减少初始页面加载时间和带宽消耗。

预加载是指在页面加载过程中提前加载某些资源,以便在用户需要这些资源时能够快速访问。这些资源可以是图片、字体、CSS 文件、JavaScript 文件等。


http://www.ppmy.cn/server/134587.html

相关文章

Spark 基础概念

Apache Spark 是一个快速、分布式的计算系统&#xff0c;用于大规模数据处理和分析。它提供了一个高级 API&#xff0c;用于编写并行处理的任务&#xff0c;可以在大规模集群上运行。 Spark 的基本概念包括以下几个方面&#xff1a; Resilient Distributed Datasets (RDDs)&a…

5. Node.js Http模块

2.4 Http模块 2.4.1创建Http服务端 //1.导入http模块 let httprequire(http)//2.创建服务对象 let serverhttp.createServer((request,response)>{console.log(request.method) //获取请求方式console.log(request.url) //获取请求url(路径和参数部份)co…

全面击破工程级复杂缓存难题

目录 一、走进业务中的缓存 &#xff08;一&#xff09;本地缓存 &#xff08;二&#xff09;分布式缓存 二、缓存更新模式分析 &#xff08;一&#xff09;Cache Aside Pattern&#xff08;旁路缓存模式&#xff09; 读操作流程 写操作流程 流程问题思考 问题1&#…

如何利用 OCR 和文档处理,快速提高供应商管理效率 ?

在当今瞬息万变的商业环境中&#xff0c;有效的供应商管理通常需要处理大量实物文档&#xff0c;这带来了巨大的挑战。手动提取供应商名称、编号和其他关键信息等关键细节非常耗时、容易出错&#xff0c;并且会降低整体效率。 为了应对这些挑战&#xff0c;组织正在逐步采用自…

什么是虚拟线程?Java 中虚拟线程的介绍与案例演示

文章目录 1. 传统线程的痛点2. 虚拟线程的优势3. 虚拟线程的实际应用场景4. 案例演示&#xff1a;如何使用虚拟线程案例 1&#xff1a;传统线程的创建案例 2&#xff1a;虚拟线程的创建案例 3&#xff1a;高并发任务中的优势 5. 总结推荐阅读文章 虚拟线程&#xff08;Virtual …

zsh: command not found: nvm 问题(Mac)

安装nvm step1: 打开终端 安装nvm brew install nvm step2: 检查是否能使用 nvm --version 然后报错出现&#xff1a;zsh: command not found: nvm 解决方法如下&#xff1a; (1): 使用vim打开.bash_profile文件进行修改 vim ~/.bash_profile按 i 键进入插入模式&#xff0c…

2010年国赛高教杯数学建模A题储油罐的变位识别与罐容表标定解题全过程文档及程序

2010年国赛高教杯数学建模 A题 储油罐的变位识别与罐容表标定 通常加油站都有若干个储存燃油的地下储油罐&#xff0c;并且一般都有与之配套的“油位计量管理系统”&#xff0c;采用流量计和油位计来测量进/出油量与罐内油位高度等数据&#xff0c;通过预先标定的罐容表&#…

Linux Redis查询key与移除日常操作

维护老项目Express node 编写的后端程序、有这么一个方法、没有设置redis过期时间&#xff08;建议设置过期时间&#xff0c;毕竟登录生产服务器并不是每个人都有权限登录的&#xff01;&#xff01;&#xff01;&#xff09;。如果变动只能通过登录生产服务器、手动修改… 于…