2024年每天10个前端小知识 【Day 11】_前端开发每日必学(1),2024年最新web前端面试题csdn

最后

小编的一位同事在校期间连续三年参加ACM-ICPC竞赛。从参赛开始,原计划每天刷一道算法题,实际上每天有时候不止一题,一年最终完成了 600+:

凭借三年刷题经验,他在校招中很快拿到了各大公司的offer。

入职前,他把他的刷题经验总结成1121页PDF书籍,作为礼物赠送给他的学弟学妹,希望同学们都能在最短时间内掌握校招常见的算法及解题思路。

整本书,我仔细看了一遍,作者非常细心地将常见核心算法题和汇总题拆分为4个章节。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

而对于有时间的同学,作者还给出了他结合众多数据结构算法书籍,挑选出的一千多道题的解题思路和方法,以供有需要的同学慢慢研究。

 var _this = this; 
 return function () { 
    console.log(_this === obj); 
 }; 

}
};


### 3. 使用Promise实现每隔1秒输出1,2,3


这道题比较简单的一种做法是可以用Promise配合着reduce不停的在promise后面叠加.then,请看下面的代码:



const arr = [1, 2, 3]
arr.reduce((p, x) => {
return p.then(() => {
return new Promise(r => {
setTimeout(() => r(console.log(x)), 1000)
})
})
}, Promise.resolve())


还可以更简单一点写:



const arr = [1, 2, 3]
arr.reduce((p, x) => p.then(() => new Promise(r => setTimeout(() => r(console.log(x)), 1000))), Promise.resolve())


### 4. 如何使用js计算一个html页面有多少种标签?


这道题看似简单,但是是一个很有价值的一道题目。它包含了很多重要的知识:


* 如何获取所有DOM节点
* 伪数组如何转为数组
* 去重


**解题过程**


* 获取所有的DOM节点。



document.querySelectorAll(‘*’)


此时得到的是一个NodeList集合,我们需要将其转化为数组,然后对其筛选。


* 转化为数组



[…document.querySelectorAll(‘*’)]


一个拓展运算符就轻松搞定。


* 获取数组每个元素的标签名



[…document.querySelectorAll(‘*’)].map(ele => ele.tagName)


使用一个map方法,将我们需要的结果映射到一个新数组。


* 去重



new Set([…document.querySelectorAll(‘*’)].map(ele=> ele.tagName)).size


我们使用ES6中的Set对象,把数组作为构造函数的参数,就实现了去重,再使用Set对象的size方法就可以得到有多少种HTML元素了。


### 5. Html文档渲染过程,css文件和js文件的下载,是否会阻塞渲染?


浏览器内有多个进程,其中渲染进程被称为浏览器内核,负责页面渲染和执行 JS 脚本等。渲染进程负责浏览器的解析和渲染,内部有 JS 引擎线程、 GUI 渲染线程、事件循环管理线程、定时器线程、HTTP 线程。  
 JS 引擎线程负责执行 JS 脚本,GUI 渲染线程负责页面的解析和渲染,两者是互斥的,也就是执行 JS 的时候页面是停止解析和渲染的。这是因为如果在页面渲染的同时 JS 引擎修改了页面元素,比如清空页面,会造成后续页面渲染的不必要和错误。而由于 JS 经常要操作 DOM ,就要涉及 JS 引擎线程和 GUI 渲染线程的通信,而线程间通信代价是非常昂贵的,这也是造成 JS 操作 DOM 效率不高的原因。  
 浏览器的 HTML/CSS 的解析和渲染都属于 GUI渲染线程,所以和 JS 引擎线程是互斥、阻塞的。下面从代码实际运行的角度分析浏览器解析和渲染的顺序,以及互相间的阻塞关系。


#### CSS 阻塞


* css 文件的下载和解析不会影响 DOM 的解析,但是会阻塞 DOM 的渲染。因为 CSSOM Tree 要和 DOM Tree 合成 Render Tree 才能绘制页面。下面的 test1 在 css 下载并解析完成前是默认样式, test2 在 css 下载并解析完成之前不会显示:



test1

test2

* css 文件没下载并解析完成之前,后续的 js 脚本不能执行。下面的 alert(‘ok’) 在 css 下载并解析完成之前不会弹出来:




* css 文件的下载不会阻塞前面的 js 脚本执行。下面的 alert(‘ok’) 会在 css 下载完成前弹出:




所以在需要提前执行不操作 dom 元素的 js 时,不妨把 js 放到 css 文件之前。


#### JS 阻塞


js 文件的下载和解析会阻塞 GUI 渲染进程,也就是会阻塞 DOM 和 CSS 的解析和渲染。


js 文件没下载并解析完成之前,后续的 HTML 和 CSS 无法解析:



test

js 文件的下载不会阻塞前面 HTML 和 CSS 的解析:



test

**需要注意的点**


* 第一,GUI 渲染线程会尽可能早的将内容呈现到屏幕上,并不会等到所有的 HTML 都解析完成之后再去构建和布局 Render Tree,而是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。下面 test1 会在 js 文件下载完成前渲染完成,而 test2 则会在 js 文件下载并执行完之后渲染:



test1
test2

* 第二,文件的下载是不会被阻塞的,不管是 css 还是 js 文件,浏览器的主线程会在页面解析前开启下载,所以就算在外部脚本执行前删除脚本,脚本也还是会下载。




### 6. forEach 中能否使用 await ?



function test() {
let arr = [3, 2, 1];
arr.forEach(async (item) => {
const res = await fetch(item);
console.log(res);
});
console.log(“end”);
}

function fetch(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x);
}, 500 * x);
});
}

test();


上面代码的输出结果是:



end
1
2
3


**为什么**


其实原因很简单,**那就是 forEach 只支持同步代码。**


我们可以参考下 Polyfill 版本的 forEach,简化以后类似就是这样的伪代码



while (index < arr.length) {
callback(item, index) //也就是我们传入的回调函数
}


从上述代码中我们可以发现,forEach 只是简单的执行了下回调函数而已,并不会去处理异步的情况。 并且即使你在 callback 中使用 break 也并不能结束遍历。


**怎么解决**


一般来说解决的办法有2种:


* for…of



//因为 for…of 内部处理的机制和 forEach 不同,forEach 是直接调用回调函数,for…of 是通过迭代器的方式去遍历。
async function test() {
let arr = [3, 2, 1];
for (const item of arr) {
const res = await fetch(item);
console.log(res);
}
console.log(“end”);
}


* for循环



async function test() {
let arr = [3, 2, 1];
for (var i = 0; i < arr.length; i++) {
const res = await fetch(arr[i]);
console.log(res);
}
console.log(“end”);
}

function fetch(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x);
}, 500 * x);
});
}

test();


### 7. 如何中断Promise?


Promise 有个缺点就是一旦创建就无法取消,所以本质上 Promise 是无法被终止的,但我们在开发过程中可能会遇到下面两个需求:


* 中断调用链


就是在某个 then/catch 执行之后,不想让后续的链式调用继续执行了。



somePromise
.then(() => {})
.then(() => {
// 终止 Promise 链,让下面的 then、catch 和 finally 都不执行
})
.then(() => console.log(‘then’))
.catch(() => console.log(‘catch’))
.finally(() => console.log(‘finally’))


一种方法是在then中直接抛错, 这样就不会执行后面的then, 直接跳到catch方法打印err(但此方法并没有实际中断)。但如果链路中对错误进行了捕获,后面的then函数还是会继续执行。


Promise的then方法接收两个参数:



Promise.prototype.then(onFulfilled, onRejected)


若onFulfilled或onRejected是一个函数,当函数返回一个新Promise对象时,原Promise对象的状态将跟新对象保持一致,详见Promises/A+标准。


因此,当新对象保持“pending”状态时,原Promise链将会中止执行。



Promise.resolve().then(() => {
console.log(‘then 1’)
return new Promise(() => {})
}).then(() => {
console.log(‘then 2’)
}).then(() => {
console.log(‘then 3’)
}).catch((err) => {
console.log(err)
})


* 中断Promise


注意这里是中断而不是终止,因为 Promise 无法终止,这个中断的意思是:在合适的时候,把 pending 状态的 promise 给 reject 掉。例如一个常见的应用场景就是希望给网络请求设置超时时间,一旦超时就就中断,我们这里用定时器模拟一个网络请求,随机 3 秒之内返回。



function timeoutWrapper(p, timeout = 2000) {
const wait = new Promise((resolve, reject) => {
setTimeout(() => {
reject(‘请求超时’)
}, timeout)
})
return Promise.race([p, wait])
}


### 8. Object.create 和 new 有什么区别?


js中创建对象的方式一般有两种Object.create和new



const Base = function(){};
const o1 = Object.create(Base);
const o2 = new Base();


在讲述两者区别之前,我们需要知道:


* 构造函数Foo的原型属性Foo.prototype指向了原型对象。
* 原型对象保存着实例共享的方法,有一个指针constructor指回构造函数。
* js中只有函数有 prototype 属性,所有的对象只有 proto 隐式属性。


那这样到底有什么不一样呢?


#### Object.create


先来看看 Object.create 的实现方式



Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};


可以看出来。Object.create是内部定义一个对象,并且让F.prototype对象 赋值为引进的对象/函数 o,并return出一个新的对象。


#### new


再看看 const o2 = new Base() 的时候,new做了什么。





### 最后

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**

❤️ 谢谢支持,喜欢的话别忘了 关注、点赞哦。

> ![前端校招面试题精编解析大全](https://img-blog.csdnimg.cn/img_convert/047080c7e128c0c90ed875c552f342f4.webp?x-oss-process=image/format,png)

 的实现方式



Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};


可以看出来。Object.create是内部定义一个对象,并且让F.prototype对象 赋值为引进的对象/函数 o,并return出一个新的对象。


#### new


再看看 const o2 = new Base() 的时候,new做了什么。





### 最后

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**

❤️ 谢谢支持,喜欢的话别忘了 关注、点赞哦。

> [外链图片转存中...(img-NbZVNysx-1715762813498)]

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值