🔥99%人只知WebP小,第3个特性却翻车?💥

🌟WebP 是什么?

WebP 是 Google 推出的一种现代图片格式,支持有损/无损压缩、透明通道(alpha)、动画,目标是"比 JPG 小 30%,比 PNG 小 80%"。

✅ 优势:

  • 体积小 → 加载快 → LCP 提升
  • 支持透明(PNG 级)
  • 支持动图(GIF 替代)
  • 渐进式加载

❌ 缺点:

  • iOS Safari < 14 不支持(2020年前)
  • 解码耗 CPU(低端机卡顿)
  • 编码慢(构建时压力大)

🧩 如何判断是否支持 WebP?

js 复制代码
function checkWebP() {
  return new Promise((resolve) => {
    const img = new Image();
    img.onload = () => resolve(true);     // 能加载成功
    img.onerror = () => resolve(false);   // 失败则不支持
    img.src = 'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA+0mEqqqqmaAA=';
  });
}

👉这行 base64 是一个 1x1 的 WebP 小图

「Q1: 为什么用 base64 而不是真实 URL?」

A1: 避免网络请求干扰,纯客户端检测 ❓

「Q2: 这个检测会影响首屏性能吗?」

A2: 会!建议缓存到 localStorage 💡

「Q3: 服务端怎么配合做降级?」

A3: 通过 Accept: image/webp 请求头判断!服务端返回对应格式 🌐


🛠️ 真实业务落地示例:电商详情页

%% ========================================================= %% 专业级「WebP 图片优化流程」架构图 %% 主题:图片格式双生成 + CDN 智能分发 + 性能优化 %% 适配:深色 / 浅色模式自适应 %% 图标:FontAwesome 6.5 %% ========================================================= %% 1. 全局样式 %% 2. 构建阶段 %% 3. CDN 分发 %% 4. 回退机制 %% 5. 性能优化 %% 6. 结果展示 flowchart LR classDef default fill:#f9fafb,stroke:#e5e7eb,color:#1f2937,stroke-width:1px,rx:8px,ry:8px classDef process fill:#0ea5e9,stroke:#0284c7,color:#fff,stroke-width:2px,rx:8px,ry:8px classDef emphasis fill:#f59e0b,stroke:#d97706,color:#fff,stroke-width:2px,rx:8px,ry:8px classDef result fill:#10b981,stroke:#059669,color:#fff,stroke-width:2px,rx:8px,ry:8px %% ========== 2. 构建阶段 ========== subgraph 构建阶段 A["
双格式生成
WebP + JPG"]:::process end %% ========== 3. CDN 分发 ========== subgraph CDN 智能分发 direction LR B["
CDN 边缘节点"]:::process B --> C["
检测请求头
Accept: image/webp"] C --> D{是否支持 WebP?} end %% ========== 4. 回退机制 ========== subgraph 兼容性处理 direction TB D -->|是| E["
返回 WebP"]:::result D -->|否| F["
返回 JPG
自动回退"]:::result end %% ========== 5. 性能优化 ========== subgraph 前端优化 G["
图片懒加载"]:::process H["
WebP 检测缓存"]:::process G --> H end %% ========== 6. 结果展示 ========== I["
首屏提速 35%
性能指标"]:::emphasis %% ========== 连接关系 ========== 构建阶段 --> CDN智能分发 CDN智能分发 --> 兼容性处理 兼容性处理 --> 前端优化 前端优化 --> I %% ========== 样式增强 ========== style A stroke-width: 3px,stroke-dasharray: 5 5 style B stroke-width: 3px,stroke-dasharray: 5 5 style G stroke-width: 3px,stroke-dasharray: 5 5 linkStyle 0 stroke:#0ea5e9,stroke-width:2px linkStyle 1 stroke:#0ea5e9,stroke-width:2px linkStyle 2 stroke:#0ea5e9,stroke-width:2px linkStyle 3 stroke:#0ea5e9,stroke-width:2px linkStyle 4 stroke:#10b981,stroke-width:3px %% ========== 动效提示 ========== %% 部署时可通过 CSS 实现: %% .node:hover { transform: scale(1.03); transition: 0.2s; } %% .edgePath:hover { stroke-width: 4px; }

🔄 连环追问链(准备接招💥):

「Q4: WebP 和 AVIF 比怎么样?🤯」

A4: AVIF 更小(50%+),但兼容性更差(Safari 16+),目前建议 WebP 为主,AVIF 试验性用

「Q5: 如何让低版本浏览器也用 WebP?👉继续看?」

A5: 不行!但可用 <picture> 标签优雅降级:

html 复制代码
<picture>
  <source srcset="img.webp" type="image/webp">
  <img src="img.jpg" alt="fallback">
</picture>

「Q6: WebP 动图能替代 GIF 吗?」

A6: 能!体积小 90%,但注意:GIF 有广泛工具链,WebP 编辑工具少 ⚠️

「Q7: 如何批量转换图片为 WebP?」

A7: Webpack 用 webp-loader,Vite 用 vite-plugin-image-presets,Node.js 用 sharp

「Q8: WebP 解码卡顿怎么破?」

A8: 控制尺寸!大图分块加载,或用 Canvas 分帧解码防主线程阻塞 💣


🌟Koa2 是什么?(顺手答了)

Koa2 是 Node.js 的轻量级 Web 框架,由 Express 原班人马打造,核心是 中间件 + async/await

js 复制代码
const Koa = require('koa');
const app = new Koa();

app.use(async (ctx, next) => {
  console.log('A');
  await next();           // 等待后续中间件
  console.log('D');
});

app.use(async (ctx) => {
  console.log('B');
  ctx.body = 'Hello';
  console.log('C');
});

// 输出:A → B → C → D

⚠️洋葱模型,你真的懂执行顺序吗?

「Q9: Koa 中间件为什么用 async 函数?」

A9: 让异步流程可 await,避免回调地狱,错误能被 try/catch 捕获 ❗

「Q10: 和 Express 中间件区别在哪?」

A10: Express 是函数调用 next(),Koa 是 await next(),控制更精细 🎯


🚀Promise 如何实现?(手撕 ≤20 行)

js 复制代码
function MyPromise(executor) {
  this.state = 'pending';
  this.value = undefined;
  this.callbacks = []; // 存储 then 回调

  const resolve = (value) => {
    if (this.state !== 'pending') return;
    this.state = 'fulfilled';
    this.value = value;
    this.callbacks.forEach(cb => cb.onResolved(value));
  };

  const reject = (reason) => {
    if (this.state !== 'pending') return;
    this.state = 'rejected';
    this.value = reason;
    this.callbacks.forEach(cb => cb.onRejected(reason));
  };

  try {
    executor(resolve, reject);
  } catch (err) {
    reject(err);
  }
}

MyPromise.prototype.then = function(onResolved, onRejected) {
  return new MyPromise((resolve, reject) => {
    // 包装回调,支持链式调用
    this.callbacks.push({
      onResolved: () => {
        const res = onResolved(this.value);
        resolve(res); // 简化版,未处理返回 Promise
      },
      onRejected: () => {
        const res = onRejected(this.value);
        reject(res);
      }
    });
  });
};

⚠️这版没处理 then 返回 Promise 的情况,面试官偷笑😏

「Q11: 如何实现 Promise.then 的链式调用?」

A11: 每次 then 返回新 Promise,并解析回调返回值(需判断是否为 Promise)🔗

「Q12: Promise.all 怎么实现?」

A12: 监控所有 Promise 状态,全 fulfilled 才 resolve,任一 reject 就 reject 🧱

「Q13: 为什么 Promise 构造函数要 try/catch?」

A13: 执行器可能抛错,需转为 reject,符合 Promise A+ 规范 📜


🌐 异步请求:低版本 fetch 如何适配?

fetch 不支持 IE,可用:

  1. polyfillwhatwg-fetch
  2. 降级到 XMLHttpRequest
  3. 构建时转换(Babel + polyfill)
js 复制代码
// 手动封装兼容层
function myFetch(url, options) {
  if (window.fetch) {
    return fetch(url, options);
  } else {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.open('GET', url);
      xhr.onload = () => resolve({ text: () => xhr.responseText });
      xhr.onerror = reject;
      xhr.send();
    });
  }
}

⚠️注意:fetch 默认不带 cookie,需加 credentials: 'include'

「Q14: fetch 和 ajax 区别?」

A14: fetch 是标准 API,返回 Promise;ajax 是 XHR 封装,更底层 🔄

「Q15: fetch 如何中断请求?」

A15: 用 AbortController + signal 传入 options 💥


🚫Ajax 如何处理跨域?

同源策略(Same-Origin Policy):协议 + 域名 + 端口 必须完全相同,否则禁止读取响应。

跨域解决方案:

方法 原理 限制
CORS 服务端加 header 需服务端配合
JSONP script 标签绕过 只能 GET
代理 本地启服务转发请求 构建时/开发用
postMessage iframe 通信 复杂,需双方配合

🔐CORS 如何设置?

服务端设置 header:

http 复制代码
Access-Control-Allow-Origin: https://a.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Credentials: true

前端发请求:

js 复制代码
fetch('http://b.com/api', {
  credentials: 'include' // 带 cookie
})

⚠️注意:*credentials: true 不能共存!

「Q16: 预检请求(preflight)什么时候触发?」

A16: 当请求是"非简单请求"时(如 PUT、带自定义 header)先发 OPTIONS 💣


❓JSONP 为什么不支持 POST?

因为 JSONP 是靠 <script src="..."> 实现的,而 script 标签只支持 GET 请求

html 复制代码
<script src="http://b.com/api?callback=fn"></script>

服务端返回:fn({"data": 1}) → 执行全局函数

「Q17: JSONP 有安全风险吗?」

A17: 有!XSS 攻击,只能用于可信接口,且需校验 referer 🔐


🔗原型链是什么?

JavaScript 通过 __proto__prototype 实现继承。

js 复制代码
function Person(name) {
  this.name = name;
}
Person.prototype.say = function() { console.log(this.name); };

const p = new Person('Tom');
p.say(); // Tom

// 查找链:p → Person.prototype → Object.prototype → null

ASCII 图示:

%% ========================================================= %% 专业级「JavaScript 原型链」可视化图 %% 主题:对象原型关系 & __proto__ 链 %% 适配:深色 / 浅色模式自适应 %% 图标:FontAwesome 6.5 %% ========================================================= %% 1. 全局样式 %% 2. 节点语义 %% 3. 关键连线 %% 4. 原型链高亮 %% 5. 动效提示 flowchart TB classDef instance fill:#f59e0b,stroke:#d97706,color:#fff,stroke-width:2px,rx:8px,ry:8px classDef prototype fill:#8b5cf6,stroke:#7c3aed,color:#fff,stroke-width:2px,rx:8px,ry:8px classDef builtin fill:#0ea5e9,stroke:#0284c7,color:#fff,stroke-width:2px,rx:8px,ry:8px classDef nullClass fill:#9ca3af,stroke:#6b7280,color:#fff,stroke-width:2px,rx:8px,ry:8px classDef function fill:#10b981,stroke:#059669,color:#fff,stroke-width:2px,rx:8px,ry:8px %% ========== 2. 节点定义 ========== P[" p (实例)"]:::instance PP[" Person.prototype"]:::prototype PS[" say()"]:::function O[" Object.prototype"]:::builtin OS[" toString()"]:::function N[" null"]:::nullClass %% ========== 3. 关键连线 ========== P -.->|__proto__| PP PP --> PS PP -.->|__proto__| O O --> OS O -.->|__proto__| N %% ========== 4. 原型链高亮 ========== linkStyle 0 stroke:#f59e0b,stroke-width:3px linkStyle 2 stroke:#8b5cf6,stroke-width:3px linkStyle 4 stroke:#0ea5e9,stroke-width:3px %% ========== 5. 动效提示 ========== %% 部署时可通过 CSS 实现: %% .node[id*="P"]:hover { transform: scale(1.05); } %% .edgePath[id*="P-PP"]:hover { stroke-width: 4px; }

⚠️每个对象都有 __proto__,函数才有 prototype

「Q18: class 是语法糖吗?」

A18: 是!class 内部还是基于原型链实现,只是更清晰 🎀


🧬如何实现继承?

  1. ES6 class 继承(推荐)
js 复制代码
class Animal { constructor(name) { this.name = name; } }
class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }
}
  1. 寄生组合继承(手写)
js 复制代码
function create(proto) {
  function F() {}
  F.prototype = proto;
  return new F();
}

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}
Dog.prototype = create(Animal.prototype);
Dog.prototype.constructor = Dog;

「Q19: 为什么不用 Dog.prototype = new Animal()?」

A19: 会执行父构造函数,可能产生无用属性,且不易传参 🤯

相关推荐
计算机毕设定制辅导-无忧学长19 分钟前
InfluxDB 集群部署与高可用方案(二)
java·linux·前端
袁煦丞25 分钟前
MongoDB数据存储界的瑞士军刀:cpolar内网穿透实验室第513号成功挑战
前端·程序员·远程工作
洛卡卡了1 小时前
面试官问限流降级,我项目根本没做过,咋办?
后端·面试·架构
天才熊猫君1 小时前
npm 和 pnpm 的一些理解
前端
飞飞飞仔1 小时前
从 Cursor AI 到 Claude Code AI:我的辅助编程转型之路
前端
qb2 小时前
vue3.5.18源码:调试方式
前端·vue.js·架构
落叶的悲哀2 小时前
面试问题11
java·数据库·面试
Spider_Man2 小时前
缓存策略大乱斗:让你的页面快到飞起!
前端·http·node.js
前端老鹰2 小时前
CSS overscroll-behavior:解决滚动穿透的 “边界控制” 专家
前端·css·html
一叶怎知秋2 小时前
【openlayers框架学习】九:openlayers中的交互类(select和draw)
前端·javascript·笔记·学习·交互