Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,他的出现大大改善了异步编程的困境,避免了地狱回调,它比传统的解决方案回调函数和事件更合理和更强大。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
(1)Promise的实例有三个状态:
当把一件事情交给promise时,它的状态就是Pending,任务完成了状态就变成了Resolved、没有完成失败了就变成了Rejected。
(2)Promise的实例有两个过程:
注意:一旦从进行状态变成为其他状态就永远不能更改状态了。
Promise的特点:
pending
(进行中)、fulfilled
(已成功)、rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是promise这个名字的由来——“承诺”;pending
变为fulfilled
,从pending
变为rejected
。这时就称为resolved
(已定型)。如果改变已经发生了,你再对promise对象添加回调函数,也会立即得到这个结果。这与事件(event)完全不同,事件的特点是:如果你错过了它,再去监听是得不到结果的。Promise的缺点:
总结: Promise 对象是异步编程的一种解决方案,最早由社区提出。Promise 是一个构造函数,接收一个函数作为参数,返回一个 Promise 实例。一个 Promise 实例有三种状态,分别是pending、resolved 和 rejected,分别代表了进行中、已成功和已失败。实例的状态只能由 pending 转变 resolved 或者rejected 状态,并且状态一经改变,就凝固了,无法再被改变了。
状态的改变是通过 resolve() 和 reject() 函数来实现的,可以在异步操作结束后调用这两个函数改变 Promise 实例的状态,它的原型上定义了一个 then 方法,使用这个 then 方法可以为两个状态的改变注册回调函数。这个回调函数属于微任务,会在本轮事件循环的末尾执行。
注意: 在构造 Promise
的时候,构造函数内部的代码是立即执行的
V8 实现了准确式 GC,GC 算法采用了分代式垃圾回收机制。因此,V8 将内存(堆)分为新生代和老生代两部分。
(1)新生代算法
新生代中的对象一般存活时间较短,使用 Scavenge GC 算法。
在新生代空间中,内存空间分为两部分,分别为 From 空间和 To 空间。在这两个空间中,必定有一个空间是使用的,另一个空间是空闲的。新分配的对象会被放入 From 空间中,当 From 空间被占满时,新生代 GC 就会启动了。算法会检查 From 空间中存活的对象并复制到 To 空间中,如果有失活的对象就会销毁。当复制完成后将 From 空间和 To 空间互换,这样 GC 就结束了。
(2)老生代算法
老生代中的对象一般存活时间较长且数量也多,使用了两个算法,分别是标记清除算法和标记压缩算法。
先来说下什么情况下对象会出现在老生代空间中:
老生代中的空间很复杂,有如下几个空间
enum AllocationSpace {
// TODO(v8:7464): Actually map this space's memory as read-only.
RO_SPACE, // 不变的对象空间
NEW_SPACE, // 新生代用于 GC 复制算法的空间
OLD_SPACE, // 老生代常驻对象空间
CODE_SPACE, // 老生代代码对象空间
MAP_SPACE, // 老生代 map 对象
LO_SPACE, // 老生代大空间对象
NEW_LO_SPACE, // 新生代大空间对象
FIRST_SPACE = RO_SPACE,
LAST_SPACE = NEW_LO_SPACE,
FIRST_GROWABLE_PAGED_SPACE = OLD_SPACE,
LAST_GROWABLE_PAGED_SPACE = MAP_SPACE
};
在老生代中,以下情况会先启动标记清除算法:
在这个阶段中,会遍历堆中所有的对象,然后标记活的对象,在标记完成后,销毁所有没有被标记的对象。在标记大型对内存时,可能需要几百毫秒才能完成一次标记。这就会导致一些性能上的问题。为了解决这个问题,2011 年,V8 从 stop-the-world 标记切换到增量标志。在增量标记期间,GC 将标记工作分解为更小的模块,可以让 JS 应用逻辑在模块间隙执行一会,从而不至于让应用出现停顿情况。但在 2018 年,GC 技术又有了一个重大突破,这项技术名为并发标记。该技术可以让 GC 扫描和标记对象时,同时允许 JS 运行。
清除对象后会造成堆内存出现碎片的情况,当碎片超过一定限制后会启动压缩算法。在压缩过程中,将活的对象向一端移动,直到所有对象都移动完成然后清理掉不需要的内存。
⽹络劫持分为两种:
(1)DNS劫持: (输⼊京东被强制跳转到淘宝这就属于dns劫持)
(2)HTTP劫持: (访问⾕歌但是⼀直有贪玩蓝⽉的⼴告),由于http明⽂传输,运营商会修改你的http响应内容(即加⼴告)
DNS劫持由于涉嫌违法,已经被监管起来,现在很少会有DNS劫持,⽽http劫持依然⾮常盛⾏,最有效的办法就是全站HTTPS,将HTTP加密,这使得运营商⽆法获取明⽂,就⽆法劫持你的响应内容。
经常遇到的问题就是Cannot read property ‘prototype’ of undefined
解决办法通过浏览器报错提示代码定位问题,解决问题
Vue项目中遇到视图不更新,方法不执行,埋点不触发等问题
一般解决方案查看浏览器报错,查看代码运行到那个阶段未之行结束,阅读源码以及相关文档等
然后举出来最近开发的项目中遇到的算是两个比较大的问题。
function Parent() {
this.a = 1;
this.b = [1, 2, this.a];
this.c = { demo: 5 };
this.show = function () {
console.log(this.a , this.b , this.c.demo );
}
}
function Child() {
this.a = 2;
this.change = function () {
this.b.push(this.a);
this.a = this.b.length;
this.c.demo = this.a++;
}
}
Child.prototype = new Parent();
var parent = new Parent();
var child1 = new Child();
var child2 = new Child();
child1.a = 11;
child2.a = 12;
parent.show();
child1.show();
child2.show();
child1.change();
child2.change();
parent.show();
child1.show();
child2.show();
输出结果:
parent.show(); // 1 [1,2,1] 5
child1.show(); // 11 [1,2,1] 5
child2.show(); // 12 [1,2,1] 5
parent.show(); // 1 [1,2,1] 5
child1.show(); // 5 [1,2,1,11,12] 5
child2.show(); // 6 [1,2,1,11,12] 5
这道题目值得神帝,他涉及到的知识点很多,例如this的指向、原型、原型链、类的继承、数据类型等。
解析:
Child
的构造函数原本是指向Child
的,题目显式将Child
类的原型对象指向了Parent
类的一个实例,需要注意Child.prototype
指向的是Parent
的实例parent
,而不是指向Parent
这个类。parent
是一个Parent
类的实例,Child.prorotype
指向的是Parent
类的另一个实例,两者在堆内存中互不影响,所以上述操作不影响parent
实例,所以输出结果不变;child1
执行了change()
方法后,发生了怎样的变化呢?Child.prototype
上的b数组,this.a会指向child1
的a属性,所以Child.prototype.b
变成了1,2,1,11;this.a
和this.b
的指向与上一句一致,故结果为child1.a
变为4;child1
自身属性并没有c这个属性,所以此处的this.c
会指向Child.prototype.c
,this.a
值为4,为原始类型,故赋值操作时会直接赋值,Child.prototype.c.demo
的结果为4,而this.a
随后自增为5(4 + 1 = 5)。child2
执行了change()
方法, 而child2
和child1
均是Child
类的实例,所以他们的原型链指向同一个原型对象Child.prototype
,也就是同一个parent
实例,所以child2.change()
中所有影响到原型对象的语句都会影响child1
的最终输出结果。Child.prototype
上的b数组,this.a会指向child2
的a属性,所以Child.prototype.b
变成了1,2,1,11,12;this.a
和this.b
的指向与上一句一致,故结果为child2.a
变为5;child2
自身属性并没有c这个属性,所以此处的this.c
会指向Child.prototype.c
,故执行结果为Child.prototype.c.demo
的值变为child2.a
的值5,而child2.a
最终自增为6(5 + 1 = 6)。window.number = 2;
var obj = {
number: 3,
db1: (function(){
console.log(this);
this.number *= 4;
return function(){
console.log(this);
this.number *= 5;
}
})()
}
var db1 = obj.db1;
db1();
obj.db1();
console.log(obj.number); // 15
console.log(window.number); // 40
这道题目看清起来有点乱,但是实际上是考察this指向的:
let arr = [1,1,"1","1",true,true,"true",{},{},"{}",null,null,undefined,undefined]
// 方法1
let uniqueOne = Array.from(new Set(arr)) console.log(uniqueOne)
// 方法2
let uniqueTwo = arr => {
let map = new Map(); //或者用空对象 let obj = {} 利用对象属性不能重复得特性
let brr = []
arr.forEach( item => {
if(!map.has(item)) { //如果是对象得话就判断 !obj[item]
map.set(item,true) //如果是对象得话就obj[item] =true 其他一样
brr.push(item)
}
})
return brr
}
console.log(uniqueTwo(arr))
//方法3
let uniqueThree = arr => {
let brr = []
arr.forEach(item => {
// 使用indexOf 返回数组是否包含某个值 没有就返回-1 有就返回下标
if(brr.indexOf(item) === -1) brr.push(item)
// 或者使用includes 返回数组是否包含某个值 没有就返回false 有就返回true
if(!brr.includes(item)) brr.push(item)
})
return brr
}
console.log(uniqueThree(arr))
//方法4
let uniqueFour = arr => {
// 使用 filter 返回符合条件的集合
let brr = arr.filter((item,index) => {
return arr.indexOf(item) === index
})
return brr
}
console.log(uniqueFour(arr))
Math.pow(2, 53) ,53 为有效数字,会发生截断,等于 JS 能支持的最大数字。
function a() {
console.log(this);
}
a.call(null);
打印结果:window对象
根据ECMAScript262规范规定:如果第一个参数传入的对象调用者是null或者undefined,call方法将把全局对象(浏览器上是window对象)作为this的值。所以,不管传入null 还是 undefined,其this都是全局对象window。所以,在浏览器上答案是输出 window 对象。
要注意的是,在严格模式中,null 就是 null,undefined 就是 undefined:
'use strict';
function a() {
console.log(this);
}
a.call(null); // null
a.call(undefined); // undefined
值得注意的是,和⼤多数浏览器不同,Chrome 浏览器的每个标签⻚都分别对应⼀个呈现引擎实例。每个标签⻚都是⼀个独⽴的进程。
1.读取缓存:
搜索自身的 DNS 缓存。(如果 DNS 缓存中找到IP 地址就跳过了接下来查找 IP 地址步骤,直接访问该 IP 地址。)
2.DNS 解析:将域名解析成 IP 地址
3.TCP 连接:TCP 三次握手,简易描述三次握手
客户端:服务端你在么?
服务端:客户端我在,你要连接我么?
客户端:是的服务端,我要链接。
连接打通,可以开始请求来
4.发送 HTTP 请求
5.服务器处理请求并返回 HTTP 报文
6.浏览器解析渲染页面
7.断开连接:TCP 四次挥手
关于第六步浏览器解析渲染页面又可以聊聊如果返回的是html页面
根据 HTML 解析出 DOM 树
根据 CSS 解析生成 CSS 规则树
结合 DOM 树和 CSS 规则树,生成渲染树
根据渲染树计算每一个节点的信息
根据计算好的信息绘制页面
gird布局,layout布局,flex布局,双飞翼,圣杯布局等
function A(){
}
function B(a){
this.a = a;
}
function C(a){
if(a){
this.a = a;
}
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;
console.log(new A().a);
console.log(new B().a);
console.log(new C(2).a);
输出结果:1 undefined 2
解析:
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0]();
}
};
obj.method(fn, 1);
输出结果: 10 2
解析:
描述:使用setTimeout
模拟实现setInterval
的功能。
实现:
const mySetInterval(fn, time) {
let timer = null;
const interval = () => {
timer = setTimeout(() => {
fn(); // time 时间之后会执行真正的函数fn
interval(); // 同时再次调用interval本身
}, time)
}
interval(); // 开始执行
// 返回用于关闭定时器的函数
return () => clearTimeout(timer);
}
// 测试
const cancel = mySetInterval(() => console.log(1), 400);
setTimeout(() => {
cancel();
}, 1000);
// 打印两次1
=>
定义,箭头函数不应用普通函数 this 绑定的四种规则,而是根据外层(函数或全局)的作用域来决定 this,且箭头函数的绑定无法被修改(new 也不行)。function foo() {
return (a) => {
console.log(this.a);
}
}
var obj1 = {
a: 2
}
var obj2 = {
a: 3
}
var bar = foo.call(obj1);
bar.call(obj2);
可以看到XSS危害如此之大, 那么在开发网站时就要做好防御措施,具体措施如下:
CSP 指的是内容安全策略,它的本质是建立一个白名单,告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截由浏览器自己来实现。 通常有两种方式来开启 CSP,一种是设置 HTTP 首部中的 Content-Security-Policy,一种是设置 meta 标签的方式
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。