2025前端社招最新面试题汇总- 场景题篇

06-01 1165阅读

1. pdf预览

// 1.href
// 2.window
window.open('a.pdf','_blank')

3. 使用 PDF.js

PDF.js是一个由 Mozilla 开发的开源库,它使用 HTML5 Canvas 来渲染 PDF 文件。PDF.js 提供了广泛的 API 来实现 PDF 的加载、渲染、缩放、打印等功能。





  // 初始化PDF.js
  pdfjsLib.getDocument("/path/to/your/document.pdf").promise.then(function (pdfDoc) {
    // 获取第一页
    pdfDoc.getPage(1).then(function (page) {
      // 设置视口和比例
      var scale = 1.5;
      var viewport = page.getViewport({ scale: scale });
      // 准备用于渲染的Canvas
      var canvas = document.createElement("canvas");
      var ctx = canvas.getContext("2d");
      canvas.height = viewport.height;
      canvas.width = viewport.width;
      // 将Canvas添加到DOM中
      document.getElementById("pdf-container").appendChild(canvas);
      // 通过Canvas渲染PDF页面
      var renderContext = {
        canvasContext: ctx,
        viewport: viewport,
      };
      page.render(renderContext);
    });
  });

使用第三方服务

也可以使用第三方服务如 Google Docs Viewer 来预览 PDF。这种方法的优点是容易实现,但依赖于外部服务。

 

其中,将http://path.to/your/document.pdf替换为你的 PDF 文件的真实 URL。

2. 日志监控问题:可有办法将请求的调用源码地址包括代码行数也上报上去?

2.1.1. 源码映射(Source Maps)

SourceMap 主要用于调试目的,让开发者能够在压缩或转译后的代码中追踪到原始代码。

webpack中 配置 devtool: 'source-map'后,

在编译过程中,会生成一个 .map 文件,一般用于代码调试和错误监控。

  • 包含了源代码、编译后的代码、以及它们之间的映射关系。
  • 编译后的文件通常会在文件末尾添加一个注释,指向 SourceMap文件的位置。
      • // # sourceMappingURL=example.js.map
        • 当在浏览器开发者工具调试时,浏览器会读取这行注释并加载对应的 SourceMap 文件

          报错时,点击跳转。即使运行的是编译后的代码,也能够追溯到原始源代码的具体位置,而不是处理经过转换或压缩后的代码,从而提高了调试效率。

          2.1.2. 自定义错误日志逻辑

          使用try .. catch 自定义报错逻辑,便于错误的追踪。

          3. 用户线上问题的解决

          首先看是否是突然性大量用户受到影响,如果是可能是上线新功能影响,则应该立即回退,降低影响范围

          然后再处理问题。复现问题-判断是前端还是后端问题。

          2025前端社招最新面试题汇总- 场景题篇

          • 浏览器缓存
          • 插件影响
          • 网络问题
          • 浏览器版本问题
          • 问题解决后需要进行复盘。

            4. 大文件上传

            • 前端上传大文件时使用 file.slice 将文件切片,并发上传多个切片(有标号, Blob 对象),最后发送一个合并的请求通知
            • 使用formData 上传文件
                • 将分块后的 Blob 对象封装到FormData中,以便通过 HTTP 请求发送。FormData对象提供了一种简单的方式来构造一个包含表单数据的对象,并且可以直接作为fetch或axios请求的body参数。
                  • 服务端合并切片
                      • 切片上传可以将上传成功的切片通过localstorage保存,再 继续上传失败的内容
                        • 服务端接收切片并存储,收到合并请求后使用流将切片合并到最终文件
                        • 原生 XMLHttpRequest 的 upload.onprogress 对切片上传进度的监听
                        • 使用 Vue 计算属性根据每个切片的进度算出整个文件的上传进度
                             
                              
                              upload
                            
                          
                          ​
                          
                          // 切片大小
                          // the chunk size
                          const SIZE = 10 * 1024 * 1024; 
                          export default {
                            data: () => ({
                              container: {
                                file: null
                              },
                              data: []
                            }),
                            methods: {
                               handleFileChange(e) {
                                const [file] = e.target.files;
                                if (!file) return;
                                Object.assign(this.$data, this.$options.data());
                                this.container.file = file;
                              },
                              // 生成文件切片
                          +    createFileChunk(file, size = SIZE) {
                          +     const fileChunkList = [];
                          +      let cur = 0;
                          +      while (cur  {
                          +          const formData = new FormData();
                          +          formData.append("chunk", chunk);
                          +          formData.append("hash", hash);
                          +          formData.append("filename", this.container.file.name);
                          +          return { formData };
                          +        })
                          +        .map(({ formData }) =>
                          +          this.request({
                          +            url: "http://localhost:3000",
                          +            data: formData
                          +          })
                          +        );
                          +      // 并发请求
                          +      await Promise.all(requestList); 
                          +    },
                          +    async handleUpload() {
                          +      if (!this.container.file) return;
                          +      const fileChunkList = this.createFileChunk(this.container.file);
                          +      this.data = fileChunkList.map(({ file },index) => ({
                          +        chunk: file,
                          +        // 文件名 + 数组下标
                          +        hash: this.container.file.name + "-" + index
                          +      }));
                          +      await this.uploadChunks();
                          +    }
                            // 合并切片
                          +     await this.mergeRequest();
                              },
                          +    async mergeRequest() {
                          +      await this.request({
                          +        url: "http://localhost:3000/merge",
                          +        headers: {
                          +          "content-type": "application/json"
                          +        },
                          +        data: JSON.stringify({
                          +          filename: this.container.file.name
                          +        })
                          +      });
                          +    },    
                            }
                          };
                          
                          

                          5. 文本点开收起展开

                          
                          
                              
                              
                              Document
                          
                          
                              
                                  这是一段可能很长的文本,我们希望在一开始时只显示部分,点击“展开”按钮后显示全部内容,再次点击则“收起”文本。
                              
                              展开
                              
                                  const button = document.getElementById('toggleButton');
                                  button.addEventListener('click', () => {
                                      const container = document.getElementById('textContainer');
                                      if (button.textContent === '展开') {
                                          button.textContent = '收起';
                                          container.style.whiteSpace = 'normal'
                                      } else {
                                          button.textContent = '展开';
                                          container.style.whiteSpace = 'nowrap'
                                      }
                                  })
                              
                              
                                  .text-overflow {
                                      width: 300px;
                                      overflow: hidden;
                                      text-overflow: ellipsis;
                                      white-space: nowrap
                                  }
                              
                          
                          
                          

                          6. 富文本划线获取

                          document.addEventListener('mouseup',(e) => {
                            const selection = window.getSelection()
                            if(selection) {
                              const res = selection.toString();
                              console.log(res)
                            }
                          })
                          

                          7. 鼠标拖拽

                          实现鼠标拖拽功能通常涉及到监听和处理鼠标事件,比如:mousedown、mousemove和mouseup事件。

                          展开
                              
                                  const button = document.getElementById("toggleButton")
                                  button.style.cursor = 'pointer'
                                  button.style.position = 'absolute'
                                  let dist = {
                                      x: 0,
                                      y: 0
                                  }
                                  let isdraggable = false;
                                  button.addEventListener('mousedown', (e) => {
                                      isdraggable = true;
                                      dist.x = e.pageX - button.offsetLeft;
                                      dist.y = e.pageY - button.offsetTop;
                                  })
                                  button.addEventListener('mousemove', (e) => {
                                      if (isdraggable) {
                                          button.style.left = e.pageX - dist.x + 'px'
                                          button.style.top = e.pageY - dist.y + 'px'
                                      }
                                  })
                                  button.addEventListener('mouseup', (e) => {
                                      if (isdraggable) {
                                          isdraggable = false;
                                          dist.x = 0
                                          dist.y = 0
                                      }
                                  })
                              
                          

                          8. 要统计全站每一个静态资源(如图片、JS 脚本、CSS 样式表等)的加载耗时

                          • 使用 PerformanceObserver : 创建一个 PerformanceObserver 实例来监听资源加载事件,能够实时收集性能数据,而且对性能影响较小。
                          • 过滤静态资源类型: 通过检查 initiatorType 属性,筛选出静态资源(例如 img、script、css 等)的加载事件。
                          • 计算和展示耗时: 对每个静态资源的加载耗时进行计算并展示。资源的耗时可以通过 duration 属性直接获取。
                            // 创建性能观察者实例来监听资源加载事件
                            const observer = new PerformanceObserver((list) => {
                              const entries = list.getEntries();
                              for (const entry of entries) {
                                // 过滤静态资源类型
                                if (["img", "script", "css", "link"].includes(entry.initiatorType)) {
                                  console.log(`资源 ${entry.name} 类型 ${entry.initiatorType} 耗时:${entry.duration.toFixed(2)} 毫秒`);
                                }
                              }
                            });
                            // 开始观察 Resource Timing 类型的性能条目
                            observer.observe({ entryTypes: ["resource"] });
                            

                            9. 如何防止前端接口重复发送

                            1、提交按钮点击后增加loading, 防止重复点击

                            2、节流或防抖

                            3、使用缓存

                            对于一些数据不经常变化的请求,例如用户信息、配置数据等,可以将请求的结果缓存起来。下一次请求相同的资源时,先从缓存中读取数据,如果缓存有效,则无需再发起新的网络请求。

                            10. 一次性渲染十万条数据

                            10.1. 全部渲染-卡死

                            这种方法虽然实现起来简单直接,但由于它在一个循环中创建并添加了所有列表项至DOM树,因此在执行过程中,浏览器需要等待JavaScript完全执行完毕才能开始渲染页面。当数据量非常大(例如本例中的100,000个列表项)时,这种大量的DOM操作会导致浏览器的渲染队列积压大量工作,从而引发页面的回流与重绘,浏览器无法进行任何渲染操作,导致了所谓的“阻塞”渲染。

                            10.2. setTimeout分批渲染 或 requestAnimationFrame

                            为了避免一次性操作引起浏览器卡顿,我们可以使用setTimeout将创建和添加操作分散到多个时间点,每次只渲染一部分数据。

                            let ul=document.getElementById('container');
                            const total=100000
                            let once= 20
                            let page=total/once
                            let index=0
                            function loop(curTotal,curIndex){
                              let pageCount=Math.min(once,curTotal)
                              setTimeout(()=>{
                                for(let i=0;i{ item.text }}
                                  
                                
                              
                             {
                                let target = document.querySelector('.' + entry.target.className + 'Li')
                                if (entry.isIntersecting) { // 出现在检测区域内
                                  document.querySelectorAll('li').forEach(el => {
                                    if(el.classList.contains('active')){
                                      el.classList.remove('active')
                                    }
                                  })
                                  if (!target.classList.contains('active')) {
                                    target.classList.add('active')
                                  }
                                }
                              })
                            }, {
                              threshold: 1
                            })
                            document.querySelectorAll('div').forEach(el => {
                              observer.observe(el)
                            })
                            

                            13. 退出浏览器之间, 发送积压的埋点数据请求

                            • fecth的 keepalive属性
                            • navigator.sendBeacon()

                              navigator.sendBeacon() 方法允许你在浏览器会话结束时异步地向服务器发送小量数据。这个方法的设计初衷就是为了解决上述问题。sendBeacon() 在大多数现代浏览器中得到支持,并且其异步特性意味着它不会阻塞页面卸载或影响用户体验。

                              window.addEventListener("beforeunload", function (event) {
                                var data = {
                                  /* 收集的埋点数据 */
                                };
                                var beaconUrl = "https://yourserver.com/path"; // 你的服务器接收端点
                                navigator.sendBeacon(beaconUrl, JSON.stringify(data));
                              });
                              

                              fetch() API 的 keepalive 选项是另一个选择。这个选项允许你发送一个保持存活状态的请求,即使用户已经离开页面。但是,需要注意的是,使用 keepalive 选项发送的请求有大小限制(大约为 64KB)。

                              window.addEventListener("beforeunload", function (event) {
                                var data = {
                                  /* 收集的埋点数据 */
                                };
                                var beaconUrl = "https://yourserver.com/path"; // 你的服务器接收端点
                                fetch(beaconUrl, {
                                  method: "POST",
                                  body: JSON.stringify(data),
                                  headers: {
                                    "Content-Type": "application/json",
                                  },
                                  keepalive: true, // 保持请求存活
                                });
                              });
                              

                              14. 代码打印

                              const { a = 1, b = 2, c = 3 } = { a: '', b: undefined, c: null };
                              // 只有设置为undefined的时候或者没有这个属性的时候才使用默认值
                              console.log(a, b, c); //    2, null 
                              // 考察运符号优先级和 加法
                              // const result = undefined || (1 + undefined) || 2;
                              // undefined转换成数字是NaN, 1+NaN = NaN
                              //  const result = undefined || NaN || 2;
                              // 最终输出2
                              const result = undefined || 1 + undefined || 2;
                              console.log(result); 
                              

                              15. 多核处理任务

                              多核环境下的性能优化需求和JavaScript特性,可采用Web Workers结合时间分片技术实现非阻塞定时任务处理。以下是基于JavaScript类的实现方案

                               // worker.js
                              self.onMessage = (data) => {
                                  const start = Date.now()
                                  while (Date.now() - start  this.#handleResult(data, worker)
                                          worker.task = null;
                                          this.workersPool.push(worker)
                                      }
                                  }
                                  addTask(input) {
                                      return new Promise((resolve, reject) => {
                                          const task = {
                                              id: Date.now(),
                                              input,
                                              resolve,
                                          }
                                          this.taskQueue.push(task)
                                          this.#run()
                                      })
                                  }
                                  #run() {
                                      if (!this.taskQueue.length) return;
                                      const availWorker = this.workersPool.find(item => !item.busy)
                                      if (!availWorker) return;
                                      availWorker.busy = true;
                                      const task = this.taskQueue.shift();
                                      availWorker.task = task;
                                      availWorker.postMessage({
                                          id: task.id,
                                          input: task.input
                                      })
                                  }
                                  #handleResult(data, worker) {
                                      worker.busy = false;
                                      worker.task.resolve(data);
                                      worker.task = null;
                                      this.#run()
                                  }
                              }
                              // 使用实例
                              const processor = new MultTask(3)
                              setInterval(() => {
                                  processor.addTask(Math.random()).then(res => console.log(res))
                              }, 40)
                              

                              16. 浏览器环境下幂级计算的优化方案

                              快速幂运算 + webworker 结合

                              快速幂算法‌

                              通过二进制分解指数,将计算复杂度从 O(n) 优化至 O(log n),减少乘法次数。例如计算 a15 时,分解为 a8×a4×a2×a1,仅需 4 次乘法而非 14 次‌

                              // worker.js
                              // // 分解为子问题计算,递归
                              function fast(a, n) {
                                if (n === 0) return 1;
                                if(n  {
                                const res = fastPower(a,n)
                                self.postmessage(res)
                              }
                              // main
                              const worker = new Worker(./worker.js)
                              worker.postmessage(2,15)
                              worker.onmessage = (res) => {
                                console.log(res)
                              }
                              

                               

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码