JS面试真题 part5

21、说说对事件循环的理解

自己回答:

js是单线程运行机制,事件分为同步事件和异步事件,就涉及到了运行时机的问题。同步任务执行完之后,会轮询异步事件队列,检查异步事件队列里是否有待执行任务。异步事件任务队列又分为宏任务队列和微任务队列,当微任务队列没有事件时,才去执行宏任务队列。源码里是没有宏任务这个概念,宏任务是一个口头概念

标准回答:

首先,JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,但这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环
JavaScript中,所有的任务都可以分为 同步任务和异步任务
同步任务和异步任务的运行流程图如下:
在这里插入图片描述
同步任务进入主线程,异步任务进入任务队列,主线程内的任务执行完毕,就会去任务队列读取对应的任务,推入主线程执行。上述过程的不断重复就是事件循环。
异步任务分为宏任务和微任务

常见的宏任务有:

  • script
  • setTimeout/setInterval
  • UI rendering/UI事件
  • postMessage、MessageChannel
  • setImmediate、I/O(Node.js)

常见的微任务有:

  • Promise.then
  • MutaionObserver
  • process.nextTick(Node.js)

事件循环、宏任务、微任务的关系如图所示:
在这里插入图片描述
流程分析:

	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')

分析:
1、遇见console.log('script start'),打印,输出script start
2、遇见定时器,加入宏任务列表
3、执行函数async1,输出async1 startasync2,后面的 console.log('async1 end')加入微任务
4、执行promise1,.then加入微任务列表
5、执行script end
6、执行微任务列表,输出async1 endpromise2
7、执行宏任务,打印settimeout

22、JavaScript本地存储方式有哪些?区别及应用场景?

自己回答:
JavaScript本地存储方式:localS、indexDB、cookie
localS:内存少(5M?),存一些关键信息
indexDB:离线缓存方案,内存大,类似前端数据库
cookie:浏览器缓存,4kb,存一些token

标准回答:

主要讲四种

  • cookie
  • sessionStorage
  • localStorage
  • indexedDB

cookie:网站为了辨别用户身份而储存在用户本地终端上的数据,为了解决HTTP无状态导致的问题。一般不超过4kb,它由一个名称(Name)、一个值(Value)和其他几个用于控制cookie有效期、安全性、使用范围的可选属性组成。cookie在每次请求中都会被发送,如果不使用https对其加密,其保存的信息很容易被窃取,导致安全风险。
localStorage:h5新方法,IE8及以上浏览器都兼容

特点:

  • 生命周期:持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的
  • 存储的信息在同一域中是共享的
  • 大小:5M(与浏览器有关系)
  • localStorage 本质上是对字符串的读取,如果存储内容多的话,会消耗内存空间,导致页面变卡。
  • 受同源策略的限制

sessionStoragesessionStoragelocalStorage使用方法基本一致,唯一不同的是生命周期,一旦页面(会话)关闭,sessionStorage将会删除数据

indexedDB:一个本地数据库,存储更大量的结构化数据。
优点:储存量理论上没有上限;所有操作是异步的,比localStorage同步操作性能更高,尤其是数据量较大时;原生支持储存JS的对象;是正经的数据库,数据库能干都能干
缺点:操作非常繁琐;有一定门槛

区别:
关于 cookie、sessionStorage、localStorage三者的区别主要如下:

  • 存储大小:cookie数据大小不能超过4ksessionStoragelocalStorage虽然也有存储大小的限制,但是比cookie大得多,可以达到5M或更大
  • 有效时间:localStorage存储持久数据,浏览器关闭后数据不丢失除非主动删除数据。sessionStorage数据在当前浏览器窗口关闭后自动删除。cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
  • 数据与服务器之间的交互方式,cookie的数据会自动的传递到服务器,服务器也可以写cookie到客户端;sessionStoragelocalStorage不会自动把数据发给服务器,仅在本地保存

应用场景

  • 标记用户与跟踪用户行为的情况,推荐使用cookie
  • 适合长期保存在本地的数据(令牌),推荐使用localStorage
  • 敏感账号一次性登录,推荐使用sessionStorage
  • 存储大量数据的情况,在线文档(富文本编辑器)保存编辑历史的情况,推荐使用indexedDB

23、大文件上传如何断点续传?

自己回答:
文件分批次上传,每个批次添加标记是否上传

标准回答:

分片上传:就是将所要上传的文件,按照一定的大小,将整个文件分割成多个数据块来进行分片上传,上传之后再由服务端对所有上传的文件进行汇总整合成原始文件
流程:
1、将需要上传的文件按照一定的分割规则,分割成相同大小的数据块;
2、初始化一个分片上传任务,返回本次分片上传唯一标识;
3、按照一定的策略(串行或并行)发送各个分片数据块;
4、发送完成后,服务端根据判断数据上传是否完整,如果完整,则进行数据块合成得到原始文件;

断点续传:指在下载或上传时,将下载或上传任务人为的划分为几个部分
每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没必要从头开始上传下载。用户可以节省时间,提高速度。
一般实现方式有两种

  • 服务器端返回,告知从哪开始
  • 浏览器自行处理

上传过程中将文件在服务器写为临时文件,等全部写完了(文件上传完),将此临时文件重命名为正式文件即可。
如果中途上传中断过,下次上传的时候根据当前临时文件大小,作为在客户端读取文件的偏移量,从此位置继续读取文件数据块,上传到服务器从此偏移量继续写入文件

实现思路:
整体思路比较简单,拿到文件,保存文件唯一标识,切割文件,分段上传,每次上传一段,根据唯一标识判断文件上传进度,直到文件的全部片段上传完毕

在这里插入图片描述
使用场景:

  • 大文件加速上传:当文件大小超过预期大小时,使用分片上传可实现并行上传多个Part,以加快上传速度
  • 网络环境较差:建议使用分片上传,当出现上传失败的时候,仅需重传失败的Part
  • 流式上传:可以在需要上传的文件大小还不确定的情况下开始上传。这种场景在视频监控等行业应用这比较常见

24、ajax原理是什么?如何实现?

自己回答:
对js的XmlHttpRequest的封装

标准回答:
AJAX全称(Async Javascript and XML)
即异步的JavascriptXML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页
AJAX的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用Javascript来操作DOM而更新页面
流程图如下:
在这里插入图片描述
实现过程:看这里浏览器请求详解(ajax、fetch、axios使用,手写ajax)

25、什么是防抖和节流?有什么区别?如何实现

自己回答:
防抖:是一段时间内防止多次点击,第一次点击后,会设置一个间隔时间,在间隔时间内点击的会重新开始间隔时间,典型应用:搜索框输入
节流:是多次重复事件,只对一次事件进行处理,典型应用:监听滚动条

标准回答:

防抖: n秒后再执行该事件,若在n秒内被重复触发,则重新计时

重置计时器:每次事件触发时,都会重置计时器。
执行时机:只有在用户停止触发事件指定时间间隔后,才会执行最后一次事件。

节流: n秒内只运行一次(第一次),若在n秒内重复触发,只有一次生效

单次执行:在时间间隔内只执行一次事件处理函数。
忽略后续触发:在时间间隔内,后续的事件触发将被忽略。

实现:

防抖:

// 创建一个防抖函数,它返回一个新的函数,该新函数在指定的 wait 时间后执行 func
function debounce(func, wait) {
    // 保存定时器的引用
    let timeout;
 
    // 返回的函数是用户实际调用的函数,它包含了防抖逻辑
    return function(...args) {
        // 保存当前的 this 上下文
        const context = this;
        console.log(context);  
 
        // 清除之前的定时器,如果存在
        if (timeout) clearTimeout(timeout);  
 
        // 设置一个新的定时器
        // 当指定的 wait 时间过后,将执行 func 函数
        // 并将当前的 this 上下文和参数传入
        timeout = setTimeout(function() {  
            // 执行原始函数,绑定正确的 this 上下文和参数
            func.apply(context, args);  
        }, wait);  
    };
}
  • 当防抖函数被触发时,首先会检查是否已经存在一个timeout(即是否有一个定时器在运行)。
  • 如果存在,表示之前有触发过防抖函数但还未执行func,此时使用clearTimeout清除之前的定时器。
  • 然后,设置一个新的timeout,如果在wait指定的时间内再次触发防抖函数,之前的定时器会被清除并重新设置,这意味着func的执行会被不断推迟。
  • 只有当指定的时间间隔wait内没有再次触发防抖函数时,timeout才会到达,此时会执行原始函数func,并且使用apply方法将存储的context和args传递给它。

节流:

function throttle(func, limit) {
    let inThrottle = false;
 
    return function(...args) {
        const context = this; // 保存当前的 this 上下文
 
        if (!inThrottle) {
            // 执行传入的函数
            func.apply(context, args);
            inThrottle = true; // 标记为正在节流
 
            // 使用闭包和 setTimeout 来在指定的延迟后重置 inThrottle
            setTimeout(() => {
                inThrottle = false; // 重置节流状态
            }, limit);
        }
    };
}
  • func:需要被节流的函数。
  • limit:表示在指定的时间间隔后,func才能再次被执行的时间(以毫秒为单位)。
  • inThrottle:一个布尔值,用来标记func是否处于可执行状态。
  • context:保存当前的this上下文,确保在执行func时this指向正确。
  • args:使用扩展运算符…来收集所有参数,以便将它们传递给func。
  • setTimeout:在指定的limit时间后执行,将inThrottle重置为false,这样func就可以在下一次调用时被执行了。

总结:

相同点:

  • 实现机制:两者都可以通过JavaScript的setTimeout函数实现,利用时间延迟来控制回调函数的执行。
  • 性能优化:它们的共同目的都是减少函数的执行频率,以此来提高程序的性能,避免不必要的计算资源消耗。

不同点:

执行时机:

  • 防抖(Debounce):确保在指定的时间间隔结束后执行一次函数。如果在这段时间内多次触发事件,则只有最后一次事件会在延迟后执行函数。
  • 节流(Throttle):确保在指定的时间间隔内最多执行一次函数。无论在这段时间内触发了多少次事件,只有第一次事件会立即执行函数。

应用场景:

  • 防抖:适用于搜索框输入、表单验证等场景,用户完成输入后,才执行相关操作。
  • 节流:适用于滚动事件、按钮点击等,需要在连续事件中合理控制执行频率的场景。

触发逻辑:

  • 防抖:关注一段时间内的连续触发,但只对最后一次操作做出响应。
  • 节流:在一段时间内,无论触发多少次事件,只响应一次。

分辨技巧:

  • 如果您希望在一系列快速操作结束后只执行一次函数,那么使用防抖。
  • 如果您希望在一系列快速操作中合理控制函数的执行频率,那么使用节流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值