发布于2021-05-30 19:26 阅读(791) 评论(0) 点赞(3) 收藏(1)
tcp/ip协议包含4层,分别是:1、应用层,为应用进程提供服务的;2、运输层;3、网络层,可以进行网络连接的建立和终止;4、网络接口层,是传输数据的物理媒介。
OSI的7层从上到下分别是 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层
进程是系统中正在运行的一个程序,程序一旦运行就是进程。进程可以看成程序执行的一个实例,可以视作为浏览器打开了多个tab页,每个tab页相当于独立的进程。进程是系统资源分配的独立实体,每个进程都拥有独立的地址空间。一个进程无法访问另一个进程的变量和数据结构,如果想让一个进程访问另一个进程的资源,需要使用进程间通信,比如管道,文件,套接字等。
一个进程可以拥有多个线程,每个线程使用其所属进程的栈空间。线程与进程的一个主要区别是,统一进程内的一个主要区别是,同一进程内的多个线程会共享部分状态,多个线程可以读写同一块内存(一个进程无法直接访问另一进程的内存)。同时,每个线程还拥有自己的寄存器和栈,其他线程可以读写这些栈内存。
程间通信的方式——信号、管道、消息队列、共享内存
验证证书 ,创建密钥,传上去验证
域名解析(递归域名),三次握手,服务器端返回请求数据,渲染页面,四次挥手
1、HTTP2使用的是二进制传送,HTTP1.X是文本(字符串)传送。二进制传送的单位是帧和流。帧组成了流,同时流还有流ID标示
2、HTTP2支持多路复用。因为有流ID,所以通过同一个http请求实现多个http请求传输变成了可能,可以通过流ID来标示究竟是哪个流从而定位到是哪个http请求
3、HTTP2头部压缩。HTTP2通过gzip和compress压缩头部然后再发送,同时客户端和服务器端同时维护一张头信息表,所有字段都记录在这张表中,这样后面每次传输只需要传输表里面的索引Id就行,通过索引ID查询表头的值
4、HTTP2支持服务器推送。HTTP2支持在未经客户端许可的情况下,主动向客户端推送内容
HTTP是一种无状态协议,即服务器不保留与客户交易时的任何状态。
用户登录后,切换到其他界面,进行操作,服务器端是无法判断是哪个用户登录的。 每次进行页面跳转的时候,得重新登录。使用Cookie session来实现有状态的http协议
cache-control: max-age=xxxx,public
客户端和代理服务器都可以缓存该资源;
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,如果用户做了刷新操作,就向服务器发起http请求
cache-control: max-age=xxxx,private
只让客户端可以缓存该资源;代理服务器不缓存
客户端在xxx秒内直接读取缓存,statu code:200
cache-control: max-age=xxxx,immutable
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,即使用户做了刷新操作,也不向服务器发起http请求
cache-control: no-cache
跳过设置强缓存,但是不妨碍设置协商缓存;一般如果你做了强缓存,只有在强缓存失效了才走协商缓存的,设置了no-cache就不会走强缓存了,每次请求都回询问服务端。
cache-control: no-store
不缓存,这个会让客户端、服务器都不缓存,也就没有所谓的强缓存、协商缓存了
etag:每个文件有一个,改动文件了就变了,就是个文件hash,每个文件唯一。
last-modified:文件的修改时间,精确到秒
ETag和Last-Modified的作用和用法,他们的区别:
1.Etag要优于Last-Modified。Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;
2.在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值;
3.在优先级上,服务器校验优先考虑Etag。
1.浏览器第一次加载资源,服务器返回200,浏览器将资源文件从服务器上请求下载下来,并把response header及该请求的返回时间一并缓存;
2.下一次加载资源时,先比较当前时间和上一次返回200时的时间差,如果没有超过cache-control设置的max-age,则没有过期,命中强缓存,不发请求直接从本地缓存读取该文件(如果浏览器不支持HTTP1.1,则用expires判断是否过期);如果时间过期,则向服务器发送header带有If-None-Match和If-Modified-Since的请求
3.服务器收到请求后,优先根据Etag的值判断被请求的文件有没有做修改,Etag值一致则没有修改,命中协商缓存,返回304;如果不一致则有改动,直接返回新的资源文件带上新的Etag值并返回200;;
4.如果服务器收到的请求没有Etag值,则将If-Modified-Since和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回304;不一致则返回新的last-modified和文件并返回200;
协议域名ip。属于浏览器的同源策略,服务器可以接受到,同源策略判断的条件是协议,域名和端口号
”JS是单线程的”指的是JS 引擎线程
在浏览器环境中,有JS 引擎线程和渲染线程,且两个线程互斥。
Node环境中,只有JS 线程。
注意:GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。
JS运行的环境。一般为浏览器或者Node
是一个存储函数调用的栈结构,遵循先进后出的原则。
JS引擎常驻于内存中,等待宿主将JS代码或函数传递给它。
也就是等待宿主环境分配宏观任务,反复等待 - 执行即为事件循环。
Event Loop中,每一次循环称为tick,每一次tick的任务如下:
ES6 规范中,microtask 称为 jobs,macrotask 称为 task
宏任务是由宿主发起的,而微任务由JavaScript自身发起。
如果设计成多个线程,线程之间dom操作矛盾会导致浏览器不知道以哪个为主,web worker可以实现多个线程,但是不能操作dom,原理上是一样的
(1) 创建一个新对象;
(2) 将构造函数中的this指向该对象
(3) 执行构造函数中的代码(为这个新对象添加属性) ;
(4) 返回新对象。
function _new(obj, ...rest){
// 基于obj的原型创建一个新的对象
const newObj = Object.create(obj.prototype);
// 添加属性到新创建的newObj上, 并获取obj函数执行的结果.
const result = obj.apply(newObj, rest);
// 如果执行结果有返回值并且是一个对象, 返回执行的结果, 否则, 返回新创建的对象
return typeof result === 'object' ? result : newObj;
}
语法糖,js的继承还是基于原型的
null
class Promsie {
constructor(fn) {
//三个状态
this.status = 'pending',
this.resolve = undefined;
this.reject = undefined;
let resolve = value => {
if (this.status === 'pending') {
this.status = 'resolved';
this.resolve = value;
}
};
let reject = value => {
if (this.status === 'pending') {
this.status = 'rejected';
this.reject = value;
}
}
try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onResolved, onRejected) {
switch (this.status) {
case 'resolved': onResolved(this.resolve); break;
case 'rejected': onRejected(this.resolve); break;
default:
}
}
}
function promiseAll(promises) {
if (!Array.isArray(promises)) {
throw new Error("promises must be an array")
}
return new Promise(function (resolve, reject) {
let promsieNum = promises.length;
let resolvedCount = 0;
let resolveValues = new Array(promsieNum);
for (let i = 0; i < promsieNum; i++) {
Promise.resolve(promises[i].then(function (value) {
resolveValues[i] = value;
resolvedCount++;
if (resolvedCount === promsieNum) {
return resolve(resolveValues)
}
}, function (reason) {
return reject(reason);
}))
}
})
}
function promiseRace(promises) {
if (!Array.isArray(promises)) {
throw new Error("promises must be an array")
}
return new Promise(function (resolve, reject) {
promises.forEach(p =>
Promise.resolve(p).then(data => {
resolve(data)
}, err => {
reject(err)
})
)
})
}
1.保护函数内的变量安全,加强了封装性 2.在内存中维持一个变量(用的太多就变成了缺点,占内存)
闭包之所以会占用资源是当函数a执行结束后, 变量i不会因为函数a的结束而销毁, 因为b的执行需要依赖a中的变量。
不适合场景:返回闭包的函数是个非常大的函数
Function.prototype.__proto__ === Object.prototype;//true
Object.__proto__ === Function.prototype;//true
Function.prototype.myCall = function(context, ...args) {
// 判断是否是undefined和null
if (typeof context === 'undefined' || context === null) {
context = window
}
let fnSymbol = Symbol()
context[fnSymbol] = this
let fn = context[fnSymbol] (...args)
delete context[fnSymbol]
return fn
}
// context[fnSymbol]中的this指向的是context
由一道字节面试题进入主题:
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function() {
console.log('settimeout')
}
async1()
new Promise(function(resolve) {
console.log('promise1')
resolve()
}).then(function() {
console.log('promise2')
})
console.log('script end')
答案:
script start
async1 start
async2
promise1
script end
async1 end
promise2
settimeout
setTimeout的回调时一个task,它会被放到宏任务的队列中,即使是0ms的情况
promise本身是同步的立即执行函数,当在executor中执行resolve或者reject的时候,此时是异步操作,会执行then、catch,这个才是异步的task,会放到微任务的栈中
async函数返回一个promise对象,当函数执行的时候,一旦遇到await就会先返回,可以理解成让出了线程,跳出了async函数体,每个await之后的操作是一个then,会被放入微任务队列中,刚开始的await之前的操作是同步的操作
async func1() {
console.log(1);
await func2(); // 让线程给func2
console.log(2); // 这一步是异步的,会被放入微任务队列
}
箭头函数体内的this对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。
var name = 'window'; // 其实是window.name = 'window'
var A = {
name: 'A',
sayHello: function(){
console.log(this.name)
}
}
A.sayHello();// 输出A
var B = {
name: 'B'
}
A.sayHello.call(B);//输出B
A.sayHello.call();//不传参数指向全局window对象,输出window.name也就是window
箭头函数的this不指向调用的对象,而指向运行时的上下文环境
var name = 'window';
var A = {
name: 'A',
sayHello: () => {
console.log(this.name)
}
}
A.sayHello();// window
怎么把sayHello的this永远绑定A?只要把箭头函数再包在一个function里即可,因为箭头函数的this永远指向运行时的环境
var name = 'window';
var A = {
name: 'A',
sayHello: function(){
var s = () => console.log(this.name)
return s//返回箭头函数s
}
}
var sayHello = A.sayHello();
sayHello();// 输出A
var B = {
name: 'B';
}
sayHello.call(B); //还是A
sayHello.call(); //还是A
flex:1
第一个参数表示: flex-grow 定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大
第二个参数表示: flex-shrink 定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小
第三个参数表示: flex-basis给上面两个属性分配多余空间之前, 计算项目是否有多余空间, 默认值为 auto, 即项目本身的大小
css实现宽高等比的矩形:用一个div包住一个div,子div设置width:100%, height: 0, padding-bottom: 对应比例,因为padding是根据宽度计算的,外层的div用来控制具体的i宽高是多少
1、组件式api的调整,将逻辑层集中了,并且抽离出了vue原先的生命周期和状态函数,可以更加灵活地调用,解决了mixin重名的问题
2、响应式实现上的调整,改用proxy去实现响应式,proxy相比defineProperty是针对一个对象的全部操作的,这样就不会有vue2不能监听到的问题
3、惰性响应式,vue2会把每一个对象数据都编程响应式的,vue3通过ref和reactive增加响应式,只需要给需要的对象或属性增加响应式
4、vue2的数据更新粒度是组件级的,对于一些静态节点,也会去遍历判断,而vue3是在编译阶段就对静态模板进行了分析,生成了block tree,这样就避免了对静态节点的不必要判断
5、vue2在父组件更新的时候,会强制使子组件更新,而vue3中优化了slot的生成,只有slot中的属性更新才会触发子组件更新
在vue文档组件模块里有介绍到单向数据流主要是避免子组件修改父组件的状态出现应用数据流混乱的状态,避免不必要的理解,维持父子组件正常的数据依赖关系。
MVC数据传递的方式是单向的
MVVM数据传递的方式是双向的
MVC:M 指的是Model(模型)是后端传递的数据,V指的是View(视图)所看到的页面,
C指的是Controller是应用程序中处理用户交互的部分
父beforeCreate -> 父created -> 父beforeMount
-> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted
-> 父mounted
PostCSS给一个组件中的所有dom添加了一个独一无二的动态属性,给css选择器额外添加一个对应的属性选择器,来选择组件中的dom,这种做法使得样式只作用于含有该属性的dom元素(组件内部的dom)
原文链接:https://blog.csdn.net/haofandedaima/article/details/117377989
作者:bbjbbh
链接:http://www.phpheidong.com/blog/article/86723/9e56b76831211787d7e7/
来源:php黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 php黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-4
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!