前端面试题手册

梳理高频技术问题,帮助你按主题复习和查漏补缺。

前端阅读 05月30日 20:13

Appium 如何测试混合应用并稳定切换 WebView?

Appium 测混合应用,关键是先分清当前操作发生在原生视图还是 WebView。原生导航栏、权限弹窗、底部 Tab 通常留在 NATIVE_APP;H5 页面里的按钮、输入框、DOM 文案要切到 WEBVIEW 后再用 CSS、XPath 或 WebDriver 定位。难点不在 API,而在 WebView 什么时候出现、Chromedriver 是否匹配、页面是否加载完成。追问什么时候需要切换到 WebView?只有目标元素属于 H5 DOM 时才切换。原生控件不要硬切 WebView 找,系统弹窗、原生返回按钮、底部导航栏通常仍在 NATIVE_APP。WebView 上下文找不到怎么排查?先确认 Android 应用开启 WebView 调试,再检查页面是否加载完成。iOS 还要确认 Web Inspector、证书和真机调试权限。Chromedriver 版本不匹配会怎样?可能能看到上下文,但切换后查 DOM 或执行 JS 报 session 错误。要配置 chromedriverExecutableDir 或自动下载策略。定位元素优先用什么?WebView 内优先稳定 CSS 或 data-testid,原生侧优先 accessibility id 或 resource-id。不要依赖易变层级 XPath。切换后为什么还要等待?上下文切换只说明进入执行环境,不代表页面元素可交互。要显式等待目标元素可见或可点击。写段代码const contexts = await driver.getContexts();const webview = contexts.find(c => c.includes('WEBVIEW'));if (webview) await driver.context(webview);
前端阅读 05月30日 20:13

Appium 如何进行数据驱动测试才稳定?

Appium 做数据驱动测试,核心是把测试步骤和测试数据拆开:脚本负责打开页面、输入、点击、断言,账号、密码、预期文案、设备差异、边界值放到 JSON、CSV、Excel、数据库或接口里。这样新增场景时通常只改数据,不改自动化逻辑,回归覆盖会稳定很多。追问数据源选 JSON、CSV 还是 Excel?JSON 适合层级结构,CSV 适合简单二维数据,Excel 对测试同学友好但 CI 里容易遇到空值类型、日期格式问题。最容易踩什么坑?测试数据之间互相污染,比如同一手机号被多条用例注册。另一个坑是只换输入不换断言,跑很多数据却没有真正覆盖业务规则。一条数据失败后要不要继续?回归场景建议继续跑,并记录 caseId、设备、输入数据、截图和关键日志。冒烟测试可以关键链路失败就中止。动态生成数据好不好?手机号、订单号适合动态生成;空密码、特殊字符等边界值最好显式写在文件里。动态数据还要有清理逻辑。和 Page Object 怎么配合?Page Object 管页面操作,数据驱动管输入和预期。用例层读取数据后调用页面方法,断言也要带 caseId。写段代码for (const tc of require('./login-cases.json').testCases) { it(`${tc.id} ${tc.description}`, async () => { await loginPage.login(tc.username, tc.password); expect(await loginPage.resultText()).toBe(tc.expected); });}
前端阅读 05月30日 19:58

Chrome 的 V8 引擎如何执行 JavaScript?

V8 执行 JavaScript 不是直接把源码一路翻成机器码。大致流程是:源码先被解析成 AST,再由 Ignition 生成并执行字节码;运行中如果某段代码频繁执行,V8 会收集类型反馈,把它交给 TurboFan 优化成机器码。优化依赖“假设”,比如对象形状稳定、函数参数类型稳定;一旦假设被打破,就会发生去优化。追问隐藏类和内联缓存是什么?V8 会给结构相似的对象建立隐藏类,用来快速定位属性。内联缓存会记录某个属性访问曾经遇到的对象形状。为什么不建议频繁 delete 属性?delete 可能改变对象形状,让原本稳定的隐藏类失效。热点路径里更常见做法是置为 null 或创建新对象。V8 的垃圾回收怎么影响页面?大量临时对象会增加 minor GC 频率,长期被闭包、全局数组、事件监听器引用的对象会进入老生代,严重时页面会间歇卡顿。代码怎么写更友好?让对象结构稳定、避免热路径混用类型、减少循环里的临时对象。先用 Performance 和 Memory 确认瓶颈,再优化热点。写段代码function makeUser(id, name) { return { id, name, active: true }; }const u = makeUser(1, 'A');u.active = false;
前端阅读 05月30日 19:58

Chrome 缓存机制有哪些?强缓存和协商缓存怎么选?

Chrome 缓存是一组从近到远的命中链路。页面请求资源时,可能先被 Service Worker 接管,再命中内存缓存或磁盘缓存;HTTP 层又分强缓存和协商缓存。强缓存看 Cache-Control: max-age,没过期就不问服务器;协商缓存会带 If-None-Match 或 If-Modified-Since 去问服务器,没变就返回 304。追问强缓存和协商缓存怎么取舍?带内容 hash 的 JS、CSS、图片适合强缓存很久;HTML 入口更适合短缓存或协商缓存,避免用户一直拿旧入口。ETag 和 Last-Modified 有什么区别?Last-Modified 依赖修改时间,精度受构建流程影响;ETag 通常基于内容或版本生成,更精确但有计算成本。memory cache 和 disk cache 有什么区别?memory cache 快,通常跟当前页面生命周期相关;disk cache 更持久。开发者主要通过 HTTP 头影响策略。Service Worker 缓存会不会覆盖 HTTP 缓存?会,它能拦截 fetch 并决定读 Cache Storage 还是走网络。缓存策略写错会导致用户长期拿旧数据。写段配置Cache-Control: public, max-age=31536000, immutableETag: "app-v42"
前端阅读 05月30日 19:58

Chrome 事件循环中宏任务和微任务到底怎么执行?

Chrome 的事件循环可以先记一句话:同步代码先进调用栈,栈清空后清空微任务,然后浏览器选择是否渲染,再执行下一个宏任务。宏任务包括 script、setTimeout、用户事件等;微任务包括 Promise.then、queueMicrotask、MutationObserver。微任务优先级高,但太多会让渲染一直没机会发生。追问setTimeout(fn, 0) 为什么不是立刻执行?它只是把回调放进宏任务队列,必须等当前同步代码和本轮微任务执行完。后台标签页和嵌套定时器还可能被节流。Promise.then 和 requestAnimationFrame 谁先执行?Promise.then 属于微任务,会在当前宏任务结束后尽快清空;rAF 通常在下一次渲染前执行。实际项目常见坑是什么?接口返回后连续触发大量 Promise 回调,在里面同步计算列表、改 DOM、再追加微任务,页面就会点击无响应。怎么拆重任务?把非关键计算切片,用 setTimeout、MessageChannel 或 requestIdleCallback 给浏览器处理输入和渲染的机会。写段代码console.log('A');setTimeout(() => console.log('B'), 0);Promise.resolve().then(() => console.log('C'));console.log('D'); // A D C B
前端阅读 05月30日 19:58

Chrome 里如何定位并优化慢网络请求?

优化 Chrome 网络请求,先用 DevTools Network 找慢在哪里。一次请求会经历 DNS、TCP/TLS、排队、TTFB、下载等阶段;不同阶段慢,处理手段完全不同。TTFB 高通常是后端或网关慢,下载慢可能是资源太大,排队多可能是连接数、优先级或主线程阻塞。追问HTTP/2 以后还要合并 JS 和 CSS 吗?不一定。HTTP/2 多路复用降低了小请求连接成本,过度合并反而会让缓存失效范围变大。preload、prefetch、preconnect 怎么选?preconnect 提前建立跨域连接;preload 抢首屏关键资源;prefetch 适合空闲加载下一页资源。Network 面板看哪些指标?先看瀑布图是否有长串阻塞,再看 Timing。TTFB、Content Download、Queueing 分别对应不同问题。缓存策略怎么避免旧资源?HTML 用短缓存或协商缓存;带 hash 的 JS、CSS、图片可设置长强缓存。没有版本号的资源不要随手缓存一年。写段代码<link rel="preconnect" href="https://cdn.example.com" crossorigin><link rel="preload" href="/assets/app.abcd.js" as="script">
前端阅读 05月30日 19:58

Chrome 为什么会拦截跨域请求?前端该怎么解决?

Chrome 拦截跨域是同源策略在保护用户数据。协议、域名、端口任意一个不同就算跨域;前端可以发起请求,但浏览器会在读取响应时检查 CORS 头。真正的解决点通常在服务端:明确允许哪些来源、方法、请求头,是否允许携带 Cookie。开发环境可以用代理绕过限制,生产不要靠关闭安全策略或插件。追问CORS 和 JSONP 有什么区别?CORS 是标准跨域机制,支持多种方法和预检;JSONP 只利用 script 标签,只能 GET,安全边界差。为什么有些请求会先发 OPTIONS?带自定义请求头、非简单方法或特殊 Content-Type 时,Chrome 会先发预检请求确认服务端是否允许。携带 Cookie 时为什么不能写 *?如果 credentials: include,服务端必须回显具体 origin,不能是星号,还要设置 Access-Control-Allow-Credentials: true。开发代理和服务端 CORS 怎么取舍?本地代理适合调试;上线后要让网关或应用服务配置 CORS,因为开发服务器代理不会跟着用户浏览器上线。写段代码res.setHeader('Access-Control-Allow-Origin', 'https://www.example.com');res.setHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization');res.setHeader('Access-Control-Allow-Credentials', 'true');
前端阅读 05月30日 19:58

Chrome 如何管理内存?V8 垃圾回收和泄漏排查怎么做?

Chrome 的内存管理主要由多进程架构、Blink 渲染管线和 V8 垃圾回收一起完成。每个标签页、iframe、扩展或站点隔离进程都可能占用独立内存;JS 对象由 V8 管,DOM、样式、图片、GPU 资源则不完全在 JS 堆里。所以排查内存问题不能只看一个数字,要分清是 JS 堆增长、DOM 节点泄漏,还是图片、Canvas、WebGL 资源没有释放。追问V8 垃圾回收大概怎么工作?V8 会把对象分成新生代和老生代,短命对象优先在新生代快速回收,存活久的对象会晋升到老生代。最常见的内存泄漏有哪些?定时器没清、事件监听没移除、全局数组当缓存、闭包引用大对象、已删除 DOM 还被 JS 变量保存,都是高频原因。Chrome DevTools 怎么排查?先用 Performance 或 Task Manager 观察内存是否持续上升,再到 Memory 面板拍 Heap Snapshot,对比 Retained Size 和 Detached DOM tree。WeakMap 能解决所有泄漏吗?不能。它适合存跟对象生命周期绑定的附加信息,但如果外部还有全局引用,WeakMap 也救不了。代码里应该怎么清理?组件卸载时清理事件、定时器和订阅,长列表做虚拟滚动,大图和 Blob URL 用完释放。const timer = setInterval(sync, 5000);window.addEventListener('resize', onResize);return () => { clearInterval(timer); window.removeEventListener('resize', onResize); };
前端阅读 05月30日 19:58

Chrome Service Worker 是什么?生命周期和缓存坑有哪些?

Service Worker 是运行在页面之外的浏览器脚本,Chrome 用它来做请求拦截、离线缓存、推送通知和后台同步。它不直接操作 DOM,也不是一直常驻后台线程,而是被 install、activate、fetch、push 等事件唤醒,处理完任务后可能被浏览器回收。理解它的关键不是背 API,而是记住:它站在页面和网络之间,但生命周期由浏览器控制。追问Service Worker 和普通 JS 脚本有什么区别?普通 JS 跟着页面走,页面关闭脚本就结束;Service Worker 注册后独立于页面。它不能访问 window 和 DOM,需要用 postMessage、Cache Storage、IndexedDB 与页面协作。install、activate、fetch 分别做什么?install 适合预缓存静态资源,activate 适合清理旧版本缓存并接管客户端,fetch 决定请求走网络还是缓存。缓存策略怎么选?静态资源通常 cache first,HTML 入口常用 network first 或 stale-while-revalidate,接口数据按业务新鲜度决定。更新为什么经常“不生效”?Chrome 发现 sw.js 字节变化后会安装新版本,但旧页面仍被旧 worker 控制,新版本要等旧页面关闭才激活。必要代码长什么样?下面只是兜底示例,真实项目要区分静态资源、HTML 和接口。self.addEventListener('fetch', event => { event.respondWith(fetch(event.request).catch(() => caches.match(event.request)));});
前端阅读 05月30日 19:58

Chrome 如何支持 PWA?安装、离线和缓存边界是什么?

Chrome 支持 PWA,靠的不是某个“打包开关”,而是浏览器把 Web App Manifest、Service Worker、HTTPS、安装入口和权限能力串在一起。页面先要像普通网站一样可访问,再通过 manifest 告诉 Chrome 应用名称、图标、启动地址、显示模式和主题色;Service Worker 负责接管部分网络请求,让核心资源可以缓存,弱网或离线时仍有可用界面。追问Chrome 判断网站能不能安装成 PWA 看什么?通常要有 HTTPS、有效 manifest、合适尺寸图标,以及可被 Service Worker 控制的页面。安装提示还会结合用户访问行为,不是文件写好就立刻弹窗。Manifest 里最容易漏掉什么?常见漏项是 start_url、scope、display 和 192/512 尺寸图标。scope 配错会让用户从图标打开后跳回普通浏览器标签页。离线能力是不是把所有接口都缓存起来?不是。HTML 壳、CSS、JS、图标适合预缓存;用户数据、价格、库存、权限状态更适合网络优先或短缓存。更新 PWA 时有什么坑?Service Worker 更新不是刷新就立即生效,新 worker 要等旧页面关闭后才接管,除非主动调用 skipWaiting 和 clients.claim。最小实现需要哪些代码?页面注册 Service Worker,worker 在 install 阶段缓存核心资源,fetch 阶段兜底返回缓存。生产还要加版本号和清理旧缓存。if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js');}