事件循环机制
- 为什么需要事件循环:
- js是单线程的,某些耗时操作会阻塞代码,所以代码/任务分同步、异步
- 同步代码交给js引擎,异步代码交给宿主环境
- 同步代码放入执行栈中,异步代码放入任务队列
- 执行栈的任务执行一个后,会到任务队列查询是否有未完成的异步任务,有就送到执行栈去执行。
微任务和宏任务
- js引入promise后,自身也可以发起异步任务了(promise本身同步,then、catch才是异步的),称为“微任务”
- 微任务是由js引擎发起
- promise(then、catch)
- process.nextTick
- Async/Await
- Object.observe
- 宏任务由宿主环境发起
- script代码块(所谓的宏任务优先是指js在script这个宏任务中执行)
- setTimeout/setInterval定时器
- setImmediate定时器
- 微任务是由js引擎发起
tcp udp
- tcp面向连接、可靠、有拥塞控制和流量控制、头部开销大,运用在文件传输
- udp面向无连接、不可靠、无拥塞控制和流量控制、头部开销小、运用在直播、音视频通话
tcp三次握手
- 为什么需要三次:防止重复连接,网络中可能存在滞留的网络请求,服务器会错误的认为发起了新的连接请求。
- 两次握手的问题:存在SYN洪水攻击风险,发送大量连接请求;且无法分辨已失效的连接请求。
暂时性死区
es6中的let和Const存在暂时性死区,意思是在块级作用域内,let和const声明的变量已经被编译器加载了,但是不能提前访问,必须在声明语句之后才能访问。该作用域开始到声明变量语句之间的区域称为暂时性死区。
不同于var,var存在变量提升,且重复声明后者会覆盖前者,但let和const不能重复声明已声明过的变量。
var a = 0;
console.log(a,window.a);// 输出 0 0
if(true){
console.log(a,window.a);// 函数声明会直接提升到块级作用域的最顶端,输出 function a 和 0
a = 1; // 取作用域最近的块级作用域的 function a ,且被重置为 1了,本质又是一个 变量的赋值。
console.log(a,window.a);// a 是指向块级作用域的 a, 输出 1 和 0
function a(){} // 函数的声明,执行函数时,变量的定义会同步到函数级作用域(即最外层)
console.log(a,window.a);// 输出 1 和 1
a = 21; // 仍然是函数定义块级作用域的 a ,重置为 21
console.log(a,window.a); // 输出为函数提升的块级作用域的 a, 输出 21,1
console.log("里面",a);//输出21
}
console.log("外部",a);//输出1
上述例子中,函数的声明会提升到块级作用域的最前面,即先var a ;再到var a = 0,函数的执行会将变量的定义提升到外部(函数级作用域)
map和普通对象
map对象和普通对象的区别:
- Map对象的键可以是任意类型的数据,而普通对象的键只能是字符串类型。
- Map对象会保持插入顺序,而普通对象不保证键值对的顺序。
- Map对象有一些特定的方法来操作和访问键值对,而普通对象使用点语法或方括号语法来操作和访问键值对。
- Map对象的键值对数量可以通过size属性获取,而普通对象需要手动计算键值对的数量。
Mixin和继承
mixin:
优点:可以将多个对象的属性组合到一个对象
缺点:可能会造成属性冲突或覆盖
继承:
优点:子类可继承父类的方法,并可重写
缺点:容易导致类层次混乱
防抖节流
防抖:
function debounce(fn, wait) {
let timer = null;
return function (...args) {
const context = this
if(timer) clearTimeout(timer); // 清除之前的定时器
timer = setTimeout(() => {
fn.apply(context,args); // 执行传入的函数,并保留函数的上下文和参数
}, wait);
};
}
节流:
function throttle(fn,interval){
let start = 0;
return function(...args){
const now = new Date().getTime()
const wait = interval - (now - start)
if(wait < 0){
fn.apply(this,args)
start = now;
}
}
}
事件捕获、执行、冒泡
<!doctype 5>
<html>
<head></head>
<body></body>
</html>
document.addEventListener('click', function(e) {
console.log(e.type, '1');
}, true);
document.body.addEventListener('click', function(e) {
console.log(e.type, '2');
e.stopPropagation();
}, true);
document.body.addEventListener('click', function(e) {
console.log(e.type, '3');
});
document.addEventListener('click', function(e) {
console.log(e.type, '4');
});
该输出结构为click 1,click 2, click 3, click 4,加了参数true即为捕获阶段执行,故事件先到document再到body,stopPropagation阻止了冒泡,所以click 1不会再输出一遍;没有参数的方法在冒泡阶段执行,此时事件到了body后向上冒泡到document;
原型、原型链
每个函数都有一个prototype属性,称为原型,存放一些属性和方法
每个实例对象都有一个__proto__属性,该属性指向它的原型对象,它原型对象也有__proto__属性,故像链表一样称为原型链;
url到页面渲染
- dns解析:域名先在本地浏览器缓存和host文件查找是否有记录,否则查询本地域名服务器-》根域名服务器-》顶级域名服务器-》返回dns地址
- 建立tcp连接:浏览器用随机端口号向服务器80端口发起tcp握手
- 发送http/https请求:https用到了ssl和tls协议加密数据。
- 服务器返回数据:返回响应头和html正文
- 浏览器解析并渲染页面:根据Html生成dom-》根据css生成cssDom-》将Dom合并-》计算dom的几何信息-》dom渲染
- 断开tcp连接:tcp四次挥手