先来回顾一下上期的问题及答案:
2023年6月15日
1. 问题:在前端开发中,什么是纹理压缩(Texture Compression)?它在游戏或图形应用中的作用是什么?请解释一种常用的纹理压缩算法。
回答:纹理压缩是一种图像压缩技术,用于减小图形应用中纹理图像的内存占用和传输带宽。在游戏或图形应用中,纹理通常用于给模型和场景添加细节和表面特性。由于纹理图像的尺寸通常较大,直接使用原始纹理图像可能会导致内存占用过高和加载时间过长。纹理压缩通过使用特定的压缩算法,可以在保持图像质量的前提下减小纹理图像的尺寸。
常用的纹理压缩算法之一是基于块的压缩算法,其中最常见的是基于DXT压缩格式。DXT算法是一种基于颜色和Alpha通道的压缩方法,可以将原始纹理图像的尺寸减小到原来的1/6或1/8,并且可以在解压缩时几乎无损地恢复原始图像。这样,游戏或图形应用可以使用更小的纹理尺寸,减少内存占用和加载时间,同时仍然保持较高的图像质量。
代码示例(使用WebGL加载并显示压缩纹理):
// 假设有一个压缩过的纹理文件 texture.dxt
const textureUrl = 'path/to/texture.dxt';const gl = canvas.getContext('webgl');// 创建纹理对象
const texture = gl.createTexture();// 加载纹理图像
const image = new Image();
image.onload = function() {// 绑定纹理对象gl.bindTexture(gl.TEXTURE_2D, texture);// 设置纹理参数gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);// 将压缩纹理图像分配给纹理对象gl.compressedTexImage2D(gl.TEXTURE_2D, 0, gl.COMPRESSED_RGBA_S3TC_DXT5_EXT, gl.TEXTURE_2D, image);// 渲染使用纹理的场景// ...
};// 加载纹理图像
image.src = textureUrl;
2. 问题:在前端开发中,什么是函数节流(Function Throttling)和函数防抖(Function Debouncing)?它们的应用场景和区别是什么?请给出一个实际的例子。
回答:函数节流和函数防抖是一种优化函数执行的技术,用于限制函数的执行频率。
函数节流(Function Throttling)是指在一定时间间隔内,无论事件触发多少次,函数只会执行一次。它适用于需要控制函数执行频率的场景,例如页面滚动事件、窗口大小调整事件等。通过函数节流,可以减少频繁触发的事件对性能的影响。
函数防抖(Function Debouncing)是指在事件触发后,等待一段时间后执行函数,如果在等待时间内再次触发事件,则重新计时。它适用于需要等待一段时间后执行的场景,例如搜索框输入事件、窗口大小调整事件等。通过函数防抖,可以减少频繁触发的事件导致的无效计算或请求。
下面是一个实际应用场景的例子,使用函数节流和函数防抖来优化事件处理:
函数节流示例:
function throttle(fn, delay) {let lastExecutionTime = 0;return function(...args) {const currentTime = Date.now();if (currentTime - lastExecutionTime >= delay) {fn.apply(this, args);lastExecutionTime = currentTime;}};
}// 滚动事件处理函数
function handleScroll() {// 处理滚动事件
}// 使用节流函数包装滚动事件处理函数,限制每200毫秒执行一次
window.addEventListener('scroll', throttle(handleScroll, 200));
函数防抖示例:
function debounce(fn, delay) {let timerId = null;return function(...args) {if (timerId) {clearTimeout(timerId);}timerId = setTimeout(() => {fn.apply(this, args);timerId = null;}, delay);};
}// 搜索框输入事件处理函数
function handleInputChange() {// 处理搜索框输入事件
}// 使用防抖函数包装搜索框输入事件处理函数,等待300毫秒后执行
searchInput.addEventListener('input', debounce(handleInputChange, 300));
3. 在前端开发中,什么是 Web Workers?它们的作用和使用场景是什么?请解释主线程和 Web Workers 之间的通信方式。
回答:
Web Workers是HTML5标准中提供的一项技术,它允许在浏览器中创建多个后台线程,独立于主线程运行。Web Workers的作用是在后台执行一些耗时的操作,以避免阻塞主线程,提高前端应用的性能和响应性。
Web Workers的使用场景包括:
执行复杂的计算:将复杂的计算任务交给Web Workers,在后台线程中执行,避免阻塞主线程,确保页面的流畅性。
大规模数据处理:处理大量数据时,可以将数据分块传递给Web Workers,进行并行处理,提高处理速度。
执行网络请求:Web Workers可以独立处理网络请求,例如发送AJAX请求或进行WebSocket通信,以避免主线程被阻塞。
主线程和Web Workers之间的通信方式主要有两种:
通过消息传递:主线程和Web Workers之间可以通过postMessage()方法发送消息,并通过onmessage事件接收消息。这种方式可以实现双向通信,在消息中传递数据和指令。
主线程发送消息给Web Workers的示例代码:
// 创建Web Worker const worker = new Worker('worker.js');// 发送消息给Web Worker worker.postMessage({ message: 'Hello from main thread!' });
Web Workers接收消息的示例代码:
// 监听消息事件 self.addEventListener('message', (event) => {const message = event.data;console.log('Received message from main thread:', message); });
通过共享内存:主线程和Web Workers可以通过SharedArrayBuffer或Transferable Objects共享内存。这种方式主要用于大规模数据的传递和共享,可以提高性能。
示例代码如下:
// 主线程创建共享内存 const sharedBuffer = new SharedArrayBuffer(1024);// 将共享内存传递给Web Worker const worker = new Worker('worker.js'); worker.postMessage(sharedBuffer);// Web Worker中访问共享内存 self.addEventListener('message', (event) => {const sharedBuffer = event.data;// 使用共享内存进行数据处理 });
注意:由于Web Workers运行在独立的线程中,它们无法直接访问DOM和一些浏览器API。如果需要在Web Workers中操作DOM或使用特定的浏览器API,可以通过消息传递与主线程进行通信,由主线程代为执行相关操作。
2023年6月16日
问题:在前端开发中,什么是服务端渲染(Server-Side Rendering,SSR)和客户端渲染(Client-Side Rendering,CSR)?请比较它们的优缺点以及适用场景。
问题:介绍一下前端中的函数柯里化(Currying)是什么?它有什么作用和优势?请给出一个函数柯里化的示例。
vue中,计算属性computed和监听watch有什么区别,应用场景是什么,各有什么优缺点。
上面问题的答案会在第二天的公众号推文中公布,大家可以关注公众号:程序员每日三问,第一时间获得推送内容。
学习不打烊,充电加油只为遇到更好的自己,每天早上9点纯手工发布面试题(死磕自己,愉悦大家) 希望大家在这浮夸的程序员圈里保持冷静,每天坚持花20分钟来学习与思考,在千变万化,类库层出不穷的今天,不要等到找工作时才狂刷题,提倡每日学习。