了解Vue3.0
手写jsonp
原理
首先简单说下跨域的概念,浏览器对不同域名,协议,端口下的请求有同源限制,服务器返回的结果,浏览器不接收。
为了解决跨域,主要有以下三种方法:jsonp、cors、ng代理.
jsonp 利用不受同源限制的img,script,frame等标签,把script标签的src指向请求的服务端地址。
1. 动态创建script标签,指定src为目标地址,将标签加到dom.body
2. 将约定好全局函数名拼接到url中
3. 清除script标签
function jsonp (url,data={},callback='callback') {
//处理json对象,拼接url
data.callback = callbak
let params = []
for(let key in data){
params.push(key + '=' + data[key])
}
let script = document.creatElement('script')
script.src = url + '?' + params.join('&')
document.body.appendChild(script)
//返回Promise
return new Promise ((resolve,reject) => {
window[callback] = (data) => {
try{
resolve (data)
} catch(e){
reject(e)
} finally {
//移除script元素
script.parentNode.removeChild(script)
console.log(script)
}
}
})
}
//请求数据
jsonp('http://photo.sina.cn/aj/index',{
page:1,
cate:'recommend',
},'jsoncallback').then(data => {
console.log(data)
})
参考链接:https://juejin.cn/post/6844903946364928008
实例
js原生获取和设置css属性
获取
1. style只能获取行间样式,能设置样式
const style = element.style.width
2. getComputedStyle能够获取行间样式/非行间样式/浏览器默认样式,不能设置样式
const style = getComputedStyle(oBox, null)['width']
兼容IE的写法(currentStyle):
function getStyle(oElement, sName){
return oElement.currentStyle ? oElement.currentStyle[sName] : getComputedStyle(oElement, null)[sName];
}
设置
1. 设置style
element.style.height = '100px';
element.style['text-align'] = '100px';
2. 设置属性
element.setAttribute('height', '100px');
element.setAttribute('height', 100);
3. 设置cssText
element.style.cssText = 'height: 100px !important';
element.style.cssText += 'height: 100px !important';
4. 设置新style标签
function addNewStyle(newStyle) {
var styleElement = document.getElementById('styles_js');
if (!styleElement) {
styleElement = document.createElement('style');
styleElement.type = 'text/css';
styleElement.id = 'styles_js';
document.getElementsByTagName('head')[0].appendChild(styleElement);
}
styleElement.appendChild(document.createTextNode(newStyle));
}
addNewStyle('.box {height: 100px !important;}');
参考
cloud.tencent.com/developer/a…
为什么要减少Dom操作?
一句话
Dom操作导致回流重绘耗费性能
详细解释
无论是React,Vue,都采用虚拟DOM的思想,其中重要的原因就是为了减少DOM操作。原因是DOM操作比较耗费性能。
耗费性能的原因简单点来说就是,每次操作DOM都会导致浏览器回流或重绘。有同学可能会问,那我只是获取一下DOM节点的信息,不更改节点属性呢?还会导致回流重绘么?
会的。 原因如下: 浏览器其实不是每一次DOM节点发生变化都重新layout跟painting,出于性能考虑会把这部分操作放在一个任务队列,在特定的时机统一处理。(浏览器会以一定的频率刷新屏幕,与这部分相关的有个API,requestAnimationsFrame,有待深挖)。但是DOM相关的操作使浏览器不得不马上执行队列中的任务,以获取最新的DOM信息。由此造成了性能的浪费。
认识WeakMap
概念
WeakMap 对象是一组键值对的集合,其中的键是弱引用对象,键值依然是正常引用。每个键对自己所引用对象的引用都是弱引用,在没有其他引用和该键引用同一对象,这个对象将会被垃圾回收(相应的key则变成无效的),所以,WeakMap 的 key 是不可枚举的。
方法
方法同map中的部分方法
has(key):判断是否有 key 关联对象
get(key):返回key关联对象(没有则则返回 undefined)
set(key):设置一组key关联对象
delete(key):移除 key 的关联对象
应用场景
发布订阅模式中,储存订阅者,若订阅者在其他地方没有被引用,则会被垃圾清除机制清除掉(如被删除的DOM节点),避免内存泄漏。
使用proxy
百看不如一用
let p = new Proxy({},{
get() {
console.log(11)
},
set() {
console.log(22)
}
})
p.b; // 11
p.b=3; // 22
p=4; // 这是改变指针,不走代理,输出nothing;原来的对象P被释放
let const 的死区
var a = 3;
function b() {
console.log(a) // error
let a = 4;
}
b()
const的不可变
const a = {};
a.b = 2
console.log(a) // {b:2}
a = {c:3} // error,不可变,指的是地址不可变,地址中存的内容可变
声明变量与函数同名的例子
console.log(a) // [Function: a]
var a = 3;
console.log(a) // 3
function a() {
console.log(1)
}
console.log(a) // 3
请用ES5,ES6实现组合继承
ES5:
function Children(){
const arg = [...arguments];
Parent.call(this,...arg);
}
Children.prototype = Object.create(Parent.prototype);
Children.prototype.constructor = Children;
ES6:
class Children extends Parent {
constructor(name) {
super();
this.name = name
}
printName() {
console.log(this.name)
}
}
资源下载的几个阶段load,DOMContentLoaded
- DOMContentLoaded:dom内容加载并解析完成的时间
- load:页面所有的资源(图片,音频,视频等)加载完成的时间
requestAnimationsFrame是什么?
概念
重绘前触发回调的API,根据浏览器刷新页面的帧率决定触发时机。 在事件循环机制中的微任务队列之后,宏任务之前。
前端路由的hash和History模式
前端路由的目的
- 记录用户操作位置,模拟浏览器前进回退功能
- 监听不同路由页面,实现不同的操作
前端路由功能
- 改变url不会向服务器发送新的请求
- 能够监听到路由的变化
两种模式比较
- hash:
- hash是url中#后面的部分
- hash变化不会导致页面刷新,会触发hashchange事件,监听这个事件实现切换页面等操作。
- hash模式下,原来的锚点功能不能用了,同时基于url传参,有体积限制。
- History模式
- 通过维护一个堆栈记录实现历史操作的记录
- 同时监听的也不是url变化,而是点击链接等操作(如a标签),先阻止默认行为,再向堆栈中添加或删除一条历史记录
- 与hash相比,刷新页面的时候还是会发送请求,如果后端没有对当前路由做处理。会返回404错误,因此History模式下要对路由做兜底,匹配不到相应路由时返回index.HTML地址。
相关API
window.history.pushState(stateObj, title, url})
window.history.replaceState(state, title, url)
// History的pushState,replaceState事件不会触发浏览器的popstate事件
// 浏览器的前进回退行为才触发
window.onpopstate = function(event){
// do something...
}
history.back();
history.go();
history.forward();
axios设置请求头
axios的get post设置请求头的参数位置不一样
axios.get("http://xxx/xxx",{
//请求头配置
headers:{ token: 21 }
//参数列表
params:{ id: 21},
}).then((res)=>{
console.log(res)
})
axios.post("http://xxx/xxx",
//参数列表
{
'id': 921
},
//请求头配置
{
headers: {'token':921 }
}
).then((res)=>{
console.log(res)
})
axios跨域请求时设置携带cookie的方法
- 在axios请求头的参数中,写入对象属性withCredentials:true
- 服务器端响应头消息中的'Access-Control-Allow-Origin'不能设置为 '*' 号,需改成具体的id地址。
- 服务器端响应头消息中必须设置 'Access-Control-Allow-Credentials':'true'。
备注:如果项目中引入了Mockjs,只要调用它的mock方法,就会劫持window的XMLHttpRequest对象,用一个自己的XHR替换,那里面withCredentials是false的,可能导致带不上cookie。可以用easymock替换,或者暂时性修复,在引入 Mock 之后使用如下代码
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
Mock.XHR.prototype.send = function () {
if (this.custom.xhr) {
this.custom.xhr.withCredentials = this.withCredentials || false
}
this.proxy_send(...arguments)
}
ajax axios fetch区别及优缺点
ajax
概念
Asynchronous Javascript And XML(异步 JavaScript 和 XML),对XHR对象的封装,浏览器创建XHR发送HTTP请求
用法
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyStatus === 4) {
// HTTP 状态在 200-300 之间表示请求成功
// HTTP 状态为 304 表示请求内容未发生改变,可直接从缓存中读取
if (xhr.status >= 200 &&
xhr.status < 300 ||
xhr.status == 304) {
console.log('请求成功', xhr.responseText)
}
}
};
xhr.open("get",url, true);
xhr.send();
// 超时时间单位为毫秒
xhr.timeout = 1000
// 当请求超时时,会触发 ontimeout 方法
xhr.ontimeout = () => console.log('请求超时')
axios
概念
基于Promise对象对xhr的封装。从浏览器中创建 XMLHttpRequests、从 node.js 创建 http 请求、支持 Promise API、拦截请求和响应等。
用法
axios.get(url)
.then(function (response) {
console.log(response);
})
.catch(error => {
console.log(error);
});
fetch
概念
原生js,基于promise设计,脱离xhr,相比其他两种更加底层的api
用法
fetch(url,{data})
.then(res => {
return response.json();
})
优缺点比较
- ajax, 底层xhr,在多个请求间有依赖关系时不好处理
- axios,非原生js,基于promise对xhr的封装,避免了回调地狱,提供了拦截请求和响应接口,自动转换JSON数据
- 防止CSRF攻击:
大概原理:
// 设置从cookie中获取csrftoken值
axios.defaults.xsrfCookieName = 'csrftoken'
// 设置将获取的token值设置到X-CSRFToken请求头中去
axios.defaults.xsrfHeaderName = "X-CSRFToken"
也可以用请求拦截实现token的获取和请求头的设置
参考链接:https://www.dazhuanlan.com/2020/03/07/5e638d7d63022
- fetch,原生js,基于promise,支持async/await,提供更加底层的API。
- 关于跨域,fetch有三个模式:
- same-origin:该模式是不允许跨域的,它需要遵守同源策略,否则浏览器会返回一个error告知不能跨域;response type:basic。
- cors: 该模式支持跨域请求,response type:cors。
- no-cors: 该模式用于跨域请求但是服务器不支持CORS;其对应的response type:opaque。这是fetch的特殊跨域请求方式,浏览器允许发送跨域请求但不能获得response内容;