Hadoop+Spark生态技术专题

JavaScript执行机制深入解析

JavaScript是单线程语言,通过事件循环机制实现异步操作。理解执行上下文、作用域链和闭包是掌握JavaScript的关键。每个函数执行都会创建一个新的执行上下文,包含变量对象、作用域链和this值。

// 执行上下文示例
function outer() {
  const a = 1;
  function inner() {
    const b = 2;
    console.log(a + b); // 访问外部作用域
  }
  return inner;
}

const fn = outer();
fn(); // 输出: 3 (闭包)

事件循环分为宏任务和微任务。宏任务包括setTimeout、setInterval、I/O操作,微任务包括Promise回调、MutationObserver。每次执行完一个宏任务后,会清空所有微任务队列。

// 事件循环执行顺序
console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => console.log('3'));

console.log('4');

// 输出顺序: 1, 4, 3, 2
// 执行流程图:
// ┌─────────────┐
// │  同步代码    │ → 1, 4
// └─────────────┘
//       ↓
// ┌─────────────┐
// │  微任务队列  │ → 3 (Promise)
// └─────────────┘
//       ↓
// ┌─────────────┐
// │  宏任务队列  │ → 2 (setTimeout)
// └─────────────┘

Promise原理与实现

Promise是解决回调地狱的优雅方案,它代表一个异步操作的最终结果。Promise有三种状态:pending、fulfilled、rejected,状态一旦改变就不会再变。链式调用通过返回新Promise实现。

// Promise状态机
class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.callbacks = [];
    
    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.callbacks.forEach(cb => cb.onFulfilled(value));
      }
    };
    
    executor(resolve);
  }
  
  then(onFulfilled) {
    return new MyPromise((resolve) => {
      if (this.state === 'fulfilled') {
        resolve(onFulfilled(this.value));
      } else {
        this.callbacks.push({ onFulfilled });
      }
    });
  }
}

/*
Promise状态转换图:
   ┌─────────┐
   │ pending │
   └────┬────┘
        │
   ┌────┴─────┐
   ▼          ▼
fulfilled  rejected
   (不可逆)
*/

async/await语法糖

async/await是Promise的语法糖,让异步代码看起来像同步代码。async函数返回Promise,await暂停函数执行等待Promise resolve。错误处理使用try/catch,比Promise的catch更直观。

// async/await最佳实践
async function fetchUserData(userId) {
  try {
    // 串行执行
    const user = await getUser(userId);
    const posts = await getPosts(user.id);
    
    // 并行执行(推荐)
    const [profile, friends] = await Promise.all([
      getProfile(user.id),
      getFriends(user.id)
    ]);
    
    return { user, posts, profile, friends };
  } catch (error) {
    console.error('获取数据失败:', error);
    throw error;
  }
}

// 执行流程:
// getUser() ──→ getPosts()
//                    ↓
//        ┌──────────────────┐
//        │ Promise.all([    │
//        │   getProfile()   │ 并行执行
//        │   getFriends()   │
//        └──────────────────┘

Vue 3响应式系统Proxy实现

Vue 3使用Proxy替代Vue 2的Object.defineProperty,实现更强大的响应式系统。Proxy可以拦截对象的所有操作,支持数组、动态属性、删除属性等场景。reactive创建响应式对象,ref创建响应式基本类型。

// Vue 3响应式原理简化版
function reactive(target) {
  return new Proxy(target, {
    get(target, key, receiver) {
      track(target, key); // 依赖收集
      return Reflect.get(target, key, receiver);
    },
    set(target, key, value, receiver) {
      const result = Reflect.set(target, key, value, receiver);
      trigger(target, key); // 触发更新
      return result;
    }
  });
}

const state = reactive({ count: 0 });

// 依赖追踪架构:
// ┌──────────────┐
// │   Component  │
// └──────┬───────┘
//        │ 读取数据
//        ▼
// ┌──────────────┐     ┌──────────────┐
// │   Proxy      │────→│  Dep收集器   │
// │  (响应式)    │     │  (依赖管理)  │
// └──────┬───────┘     └──────┬───────┘
//        │ 数据变化            │
//        └─────────────────────┘
//                │ 触发更新
//                ▼
//        ┌──────────────┐
//        │   re-render  │
//        └──────────────┘

React Hooks原理与闭包陷阱

React Hooks通过链表结构存储状态,每次render按顺序调用hooks。这就是为什么hooks不能在条件语句中使用。useEffect的依赖数组决定何时执行副作用,闭包陷阱是常见问题。

// Hooks闭包陷阱示例
function Counter() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    const timer = setInterval(() => {
      // 错误:永远读取的是初始count值(0)
      // console.log(count);
      
      // 正确:使用函数式更新
      setCount(c => c + 1);
    }, 1000);
    
    return () => clearInterval(timer);
  }, []); // 空依赖数组
  
  return <div>{count}</div>;
}

// Hooks链表结构:
// Fiber节点
//    │
//    ├─→ Hook1 (useState) ──→ Hook2 (useEffect)
//    │      │                      │
//    │   state: 0              deps: []
//    │   queue: []            effect: fn
//    │
//    └─→ 下次render时按相同顺序访问

TypeScript高级类型推导

TypeScript的类型系统图灵完备,可以实现复杂的类型推导。泛型、条件类型、映射类型、模板字面量类型等特性组合使用,可以实现类型体操。理解协变和逆变对写好类型很重要。

// 工具类型实现
// 1. 深度只读
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object
    ? DeepReadonly<T[K]>
    : T[K];
};

// 2. 获取函数返回值类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// 3. 路径类型推导
type PathOf<T> = {
  [K in keyof T]: K extends string
    ? T[K] extends object
      ? `${K}.${PathOf<T[K]>}` | K
      : K
    : never;
}[keyof T];

// 类型推导流程:
// Input Type
//     │
//     ├─→ 条件类型判断 (extends)
//     │        │
//     │        ├─→ True分支: infer提取类型
//     │        └─→ False分支: 返回默认类型
//     │
//     └─→ Output Type

Webpack构建流程与优化

Webpack构建流程包括初始化、编译、输出三个阶段。理解Loader和Plugin的工作机制是优化构建的基础。Loader处理文件转换,Plugin监听构建事件执行自定义逻辑。

// Webpack配置优化
module.exports = {
  mode: 'production',
  
  // 代码分割
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10
        }
      }
    }
  },
  
  // 缓存优化
  cache: {
    type: 'filesystem',
    buildDependencies: {
      config: [__filename]
    }
  },
  
  // Loader配置
  module: {
    rules: [{
      test: /\.js$/,
      use: ['thread-loader', 'babel-loader'],
      exclude: /node_modules/
    }]
  }
};

// 构建流程图:
// ┌────────────┐
// │ Entry入口  │
// └─────┬──────┘
//       │
//       ▼
// ┌────────────┐    ┌──────────┐
// │ 解析依赖树 │───→│ Loader   │
// └─────┬──────┘    │ 转换文件 │
//       │           └──────────┘
//       ▼
// ┌────────────┐    ┌──────────┐
// │ 构建模块   │───→│ Plugin   │
// └─────┬──────┘    │ 自定义逻辑│
//       │           └──────────┘
//       ▼
// ┌────────────┐
// │ 输出Bundle │
// └────────────┘

浏览器渲染原理与优化

浏览器渲染分为解析HTML、样式计算、布局、绘制、合成五个阶段。重排(reflow)和重绘(repaint)是性能瓶颈。理解关键渲染路径可以优化首屏加载速度。

// 避免强制同步布局
// ❌ 不好的做法
function badPractice() {
  const width = element.offsetWidth; // 读取触发布局
  element.style.width = width + 10 + 'px'; // 写入
  // 重复N次会导致布局抖动
}

// ✅ 好的做法
function goodPractice() {
  // 批量读取
  const width = element.offsetWidth;
  
  // 使用requestAnimationFrame批量写入
  requestAnimationFrame(() => {
    element.style.width = width + 10 + 'px';
  });
}

// 渲染管道:
// HTML ──→ DOM树 ──┐
//                   ├──→ 渲染树 ──→ 布局 ──→ 绘制 ──→ 合成
// CSS  ──→ CSSOM ──┘
//
// 优化策略:
// 1. 减少DOM操作 (DocumentFragment)
// 2. CSS放<head>,JS放</body>前
// 3. 使用transform/opacity触发合成
// 4. 虚拟滚动处理长列表

常用算法实现与分析

算法的时间复杂度和空间复杂度决定了程序性能。排序算法、搜索算法、动态规划是面试重点。理解算法背后的思想比记住代码更重要。

// 快速排序实现
function quickSort(arr) {
  if (arr.length <= 1) return arr;
  
  const pivot = arr[Math.floor(arr.length / 2)];
  const left = arr.filter(x => x < pivot);
  const middle = arr.filter(x => x === pivot);
  const right = arr.filter(x => x > pivot);
  
  return [...quickSort(left), ...middle, ...quickSort(right)];
}

// 二分查找
function binarySearch(arr, target) {
  let left = 0, right = arr.length - 1;
  
  while (left <= right) {
    const mid = Math.floor((left + right) / 2);
    if (arr[mid] === target) return mid;
    if (arr[mid] < target) left = mid + 1;
    else right = mid - 1;
  }
  
  return -1;
}

// 快排分治过程:
//     [5, 2, 8, 1, 9]
//          ↓ pivot=8
//    ┌─────┴─────┐
//  [5,2,1]      [9]
//    ↓ pivot=2
//  ┌─┴─┐
// [1] [5]
//
// 时间复杂度:
// - 平均: O(n log n)
// - 最坏: O(n²)

JavaScript设计模式实战

设计模式是解决常见问题的最佳实践。单例模式、工厂模式、观察者模式在JavaScript中应用广泛。理解设计原则SOLID比死记模式更重要。

// 1. 单例模式
class Singleton {
  static instance = null;
  
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    Singleton.instance = this;
  }
}

// 2. 观察者模式
class EventEmitter {
  constructor() {
    this.events = {};
  }
  
  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
  }
  
  emit(event, data) {
    if (this.events[event]) {
      this.events[event].forEach(cb => cb(data));
    }
  }
}

// 观察者模式架构:
//     ┌──────────┐
//     │  Subject │ (被观察者)
//     └────┬─────┘
//          │ notify()
//     ┌────┼────┬─────┐
//     │    │    │     │
//     ▼    ▼    ▼     ▼
//  Observer1 Observer2 ... (观察者)
//  update()  update()

HTTP协议与网络优化

HTTP/1.1的队头阻塞问题通过HTTP/2的多路复用解决。HTTP/3使用QUIC协议基于UDP,进一步提升性能。理解缓存策略可以减少不必要的网络请求。

// HTTP缓存策略
// 1. 强缓存
Cache-Control: max-age=3600, public
Expires: Wed, 21 Oct 2025 07:28:00 GMT

// 2. 协商缓存  
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT
If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT

// HTTP/2多路复用:
// HTTP/1.1:
// Request1 ──→ Response1 ──→ Request2 ──→ Response2
//              (队头阻塞)
//
// HTTP/2:
// ┌─ Stream1: Request1  ──→ Response1
// ├─ Stream2: Request2  ──→ Response2  (并行)
// └─ Stream3: Request3  ──→ Response3
//     同一个TCP连接

// Fetch API实现
fetch('/api/data', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json'
  },
  cache: 'no-cache' // 缓存策略
})

Node.js架构与最佳实践

Node.js基于V8引擎和libuv,通过事件驱动和非阻塞I/O实现高并发。理解EventLoop的各个阶段对写好Node.js应用很重要。使用Stream处理大文件可以降低内存占用。

// Stream处理大文件
const fs = require('fs');
const { pipeline } = require('stream');

// 读取大文件并压缩
pipeline(
  fs.createReadStream('large-file.txt'),
  zlib.createGzip(),
  fs.createWriteStream('large-file.txt.gz'),
  (err) => {
    if (err) console.error('Pipeline失败:', err);
    else console.log('Pipeline成功');
  }
);

// Node.js架构:
// ┌─────────────────────────────┐
// │      JavaScript代码         │
// ├─────────────────────────────┤
// │      Node.js Bindings       │
// ├─────────────────────────────┤
// │  V8引擎  │     libuv         │
// │ (JS执行) │ (事件循环/异步I/O)│
// └──────────┴──────────────────┘
//             │
//     ┌───────┼───────┐
//     ▼       ▼       ▼
//   文件系统 网络  线程池

// 中间件模式
app.use((req, res, next) => {
  console.log('请求:', req.url);
  next(); // 传递给下一个中间件
});

数据库设计与索引优化

良好的数据库设计是系统性能的基础。数据库范式规范数据结构,但有时为了性能需要反范式化。索引可以加速查询但会降低写入速度,需要权衡。

-- 索引创建与查询优化
-- 创建联合索引
CREATE INDEX idx_user_age_city 
ON users(age, city);

-- 好的查询(使用索引)
SELECT * FROM users 
WHERE age = 25 AND city = 'Beijing';

-- 不好的查询(索引失效)
SELECT * FROM users 
WHERE city = 'Beijing'; -- 未使用最左前缀

-- 使用EXPLAIN分析
EXPLAIN SELECT * FROM users WHERE age > 25;

/*
索引结构 (B+树):
        [30]
       /    \
    [10,20] [40,50]
      │      │
    叶子节点存储数据指针
    
查询流程:
1. 从根节点开始
2. 比较查找键值
3. 定位到叶子节点
4. 获取数据

最佳实践:
- WHERE/ORDER BY字段建索引
- 避免SELECT *
- 使用覆盖索引
- 分析慢查询日志
*/

Redis数据结构与应用场景

Redis支持丰富的数据结构,每种结构都有特定的应用场景。String用于缓存,Hash存储对象,List实现队列,Set去重,Sorted Set实现排行榜。

// Redis数据结构应用
const redis = require('redis');
const client = redis.createClient();

// 1. String - 缓存
await client.setEx('user:1001', 3600, JSON.stringify(user));

// 2. Hash - 存储对象
await client.hSet('user:1001', {
  name: 'Alice',
  age: 25,
  city: 'Beijing'
});

// 3. List - 消息队列
await client.rPush('queue:tasks', task1, task2);
const task = await client.lPop('queue:tasks');

// 4. Sorted Set - 排行榜
await client.zAdd('rank:score', [
  { score: 100, value: 'user1' },
  { score: 95, value: 'user2' }
]);

// 数据结构选择:
// String  → 简单KV、计数器、分布式锁
// Hash    → 对象存储、购物车
// List    → 消息队列、最新列表
// Set     → 去重、共同好友
// ZSet    → 排行榜、延时队列
//
// 缓存策略:
// ┌──────┐  ┌──────┐  ┌──────┐
// │ 读取 │─→│ 缓存 │─→│ 数据库│
// └──────┘  └──┬───┘  └──────┘
//              │
//           命中/未命中

Docker容器化与编排

Docker通过容器技术实现应用隔离和部署一致性。Dockerfile定义镜像构建步骤,docker-compose管理多容器应用。理解镜像分层和缓存机制可以优化构建速度。

# 多阶段构建Dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:18-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .

EXPOSE 3000
CMD ["node", "server.js"]

# docker-compose.yml
version: '3.8'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - redis
      
  redis:
    image: redis:alpine
    ports:
      - "6379:6379"

# 容器架构:
# ┌────────────────────────────┐
# │      Docker Host           │
# │  ┌──────┐  ┌──────┐       │
# │  │ Web  │  │Redis │       │
# │  │容器  │──│容器  │       │
# │  └──────┘  └──────┘       │
# │      Docker Engine         │
# └────────────────────────────┘
#            │
#        宿主机OS

微服务架构设计模式

微服务将单体应用拆分为独立服务,每个服务负责单一业务功能。服务间通过API通信,可以独立部署和扩展。需要解决服务发现、配置管理、分布式事务等问题。

// API网关模式
class APIGateway {
  async route(request) {
    const { path, method } = request;
    
    // 路由到不同的微服务
    if (path.startsWith('/users')) {
      return await this.userService.handle(request);
    }
    if (path.startsWith('/orders')) {
      return await this.orderService.handle(request);
    }
    
    throw new Error('Service not found');
  }
  
  // 熔断器模式
  async callWithCircuitBreaker(service, request) {
    if (this.circuitOpen) {
      throw new Error('Circuit breaker is open');
    }
    
    try {
      return await service(request);
    } catch (error) {
      this.failureCount++;
      if (this.failureCount > threshold) {
        this.circuitOpen = true;
      }
      throw error;
    }
  }
}

// 微服务架构图:
//        ┌──────────┐
//        │API Gateway│
//        └────┬─────┘
//             │
//   ┌─────────┼─────────┐
//   ▼         ▼         ▼
// ┌────┐  ┌────┐  ┌────┐
// │User│  │Order│ │Pay │
// │服务│  │服务 │ │服务│
// └─┬──┘  └─┬──┘  └─┬──┘
//   │       │       │
//   ▼       ▼       ▼
//  DB1     DB2     DB3

Web安全攻击与防御

Web安全是应用开发的基础。XSS通过注入脚本窃取信息,CSRF利用用户身份发起攻击,SQL注入破坏数据库。了解攻击原理才能有效防御。

// 1. XSS防御 - 输出编码
function escapeHtml(unsafe) {
  return unsafe
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

// 2. CSRF防御 - Token验证
app.post('/transfer', (req, res) => {
  const token = req.headers['csrf-token'];
  if (!validateCSRFToken(token)) {
    return res.status(403).send('Invalid token');
  }
  // 执行转账操作
});

// 3. SQL注入防御 - 参数化查询
// ❌ 危险
const query = `SELECT * FROM users WHERE id = ${userId}`;

// ✅ 安全
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId]);

// 安全防御层次:
// ┌─────────────────┐
// │   输入验证      │ 第一道防线
// ├─────────────────┤
// │   输出编码      │ XSS防御
// ├─────────────────┤
// │   参数化查询    │ SQL注入防御
// ├─────────────────┤
// │   HTTPS加密     │ 传输安全
// └─────────────────┘

GraphQL vs REST API设计

GraphQL提供了一种更灵活的API查询方式。客户端可以精确指定需要的数据,避免over-fetching和under-fetching。强类型Schema提供了良好的开发体验和自动文档生成。

// GraphQL Schema定义
type User {
  id: ID!
  name: String!
  email: String!
  posts: [Post!]!
}

type Post {
  id: ID!
  title: String!
  content: String!
  author: User!
}

type Query {
  user(id: ID!): User
  posts: [Post!]!
}

// GraphQL查询
query GetUserWithPosts {
  user(id: "123") {
    name
    email
    posts {
      title
      content
    }
  }
}

// REST vs GraphQL:
// REST:
// GET /users/123        → 用户信息(可能包含不需要的字段)
// GET /users/123/posts  → 用户文章(需要多次请求)
//
// GraphQL:
// POST /graphql
// { 一次请求获取精确数据 }
//
// Resolver流程:
// Query ──→ Resolver ──→ DataSource
//   │          │             │
//   └──────────┴─────────────┘
//         返回精确数据

WebSocket实时通信实现

WebSocket提供全双工通信,服务器可以主动推送数据。相比HTTP轮询更高效,适合实时应用如聊天、游戏、协同编辑。需要处理心跳检测、断线重连等问题。

// WebSocket客户端实现
class WSClient {
  constructor(url) {
    this.url = url;
    this.ws = null;
    this.reconnectDelay = 1000;
    this.heartbeatInterval = 30000;
    this.connect();
  }
  
  connect() {
    this.ws = new WebSocket(this.url);
    
    this.ws.onopen = () => {
      console.log('连接成功');
      this.startHeartbeat();
    };
    
    this.ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      this.handleMessage(data);
    };
    
    this.ws.onclose = () => {
      console.log('连接断开,尝试重连...');
      setTimeout(() => this.connect(), this.reconnectDelay);
    };
  }
  
  startHeartbeat() {
    this.heartbeatTimer = setInterval(() => {
      this.send({ type: 'ping' });
    }, this.heartbeatInterval);
  }
  
  send(data) {
    if (this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(data));
    }
  }
}

// WebSocket通信流程:
// Client              Server
//   │ ─── HTTP握手 ──→  │
//   │ ←── 升级协议 ───  │
//   │                   │
//   │ ←─── 数据推送 ─→  │ (全双工)
//   │                   │
//   │ ─── 心跳ping ──→  │
//   │ ←─── pong ──────  │

服务端渲染与静态生成

SSR在服务器端渲染HTML,提升首屏速度和SEO。SSG在构建时生成静态HTML,性能最优。ISR结合两者优点,可以增量更新静态页面。Next.js和Nuxt.js提供了完善的SSR解决方案。

// Next.js渲染模式
// 1. SSR - 服务端渲染
export async function getServerSideProps(context) {
  const res = await fetch(`https://api.example.com/data`);
  const data = await res.json();
  
  return { props: { data } };
}

// 2. SSG - 静态生成
export async function getStaticProps() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();
  
  return {
    props: { posts },
    revalidate: 60 // ISR: 60秒后重新生成
  };
}

// 3. CSR - 客户端渲染
function Page() {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    fetch('/api/data').then(res => res.json()).then(setData);
  }, []);
  
  return <div>{data?.title}</div>;
}

// 渲染模式对比:
//        首屏速度  SEO  服务器负载  交互性
// SSR      快     好      高       好
// SSG     最快    好      低       好
// CSR      慢     差      低       好
//
// 选择策略:
// 博客/文档  → SSG
// 电商首页  → SSR
// 管理后台  → CSR

前端测试金字塔

测试金字塔建议70%单元测试、20%集成测试、10%E2E测试。单元测试成本低、速度快,应该覆盖核心业务逻辑。集成测试验证组件协作。E2E测试模拟真实用户操作。

// Jest单元测试
describe('Calculator', () => {
  test('adds 1 + 2 to equal 3', () => {
    expect(add(1, 2)).toBe(3);
  });
  
  test('handles edge cases', () => {
    expect(add(0, 0)).toBe(0);
    expect(add(-1, 1)).toBe(0);
  });
});

// React Testing Library
import { render, screen, fireEvent } from '@testing-library/react';

test('button click increments counter', () => {
  render(<Counter />);
  const button = screen.getByText('Increment');
  
  fireEvent.click(button);
  
  expect(screen.getByText('Count: 1')).toBeInTheDocument();
});

// Cypress E2E测试
describe('Login Flow', () => {
  it('should login successfully', () => {
    cy.visit('/login');
    cy.get('[data-testid="username"]').type('admin');
    cy.get('[data-testid="password"]').type('password');
    cy.get('[data-testid="submit"]').click();
    cy.url().should('include', '/dashboard');
  });
});

// 测试金字塔:
//       ╱ ╲
//      ╱E2E╲      10% - 慢、昂贵、脆弱
//     ╱─────╲
//    ╱集成测试╲    20% - 中等速度和成本
//   ╱─────────╲
//  ╱  单元测试  ╲  70% - 快、便宜、稳定
// ╱─────────────╲

CI/CD流水线设计

持续集成确保代码质量,持续部署实现快速交付。GitHub Actions、GitLab CI、Jenkins是常用的CI/CD工具。合理的流水线设计可以提高开发效率,减少人为错误。

# GitHub Actions工作流
name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run tests
        run: npm test
      
      - name: Build
        run: npm run build
  
  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Deploy to production
        run: |
          echo "Deploying to prod..."
          # 部署脚本

# CI/CD流程图:
# 代码提交
#     │
#     ├─→ Lint检查
#     ├─→ 单元测试
#     ├─→ 集成测试
#     ├─→ 构建打包
#     │
#     ▼
# ┌─────────┐    ┌─────────┐    ┌─────────┐
# │ 开发环境 │───→│ 测试环境 │───→│ 生产环境 │
# └─────────┘    └─────────┘    └─────────┘
#   自动部署      手动审批       金丝雀发布

前端性能监控体系

前端监控包括性能监控、错误监控、用户行为监控。通过Performance API收集性能数据,通过错误捕获机制收集异常。数据上报使用sendBeacon或Image对象,避免影响用户体验。

// 性能监控
class PerformanceMonitor {
  constructor() {
    this.observer = new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        this.reportMetric(entry);
      }
    });
    
    this.observer.observe({ 
      entryTypes: ['navigation', 'paint', 'largest-contentful-paint'] 
    });
  }
  
  reportMetric(entry) {
    const data = {
      name: entry.name,
      value: entry.startTime,
      type: entry.entryType
    };
    
    // 使用sendBeacon上报
    navigator.sendBeacon('/api/metrics', JSON.stringify(data));
  }
}

// 错误监控
window.addEventListener('error', (event) => {
  const errorData = {
    message: event.message,
    filename: event.filename,
    lineno: event.lineno,
    colno: event.colno,
    stack: event.error?.stack
  };
  
  reportError(errorData);
});

// 监控架构:
// ┌─────────────┐
// │   前端应用   │
// └──────┬──────┘
//        │ 采集数据
//        ▼
// ┌─────────────┐
// │ SDK/埋点代码 │
// └──────┬──────┘
//        │ 上报
//        ▼
// ┌─────────────┐    ┌─────────────┐
// │  数据收集    │───→│  数据分析   │
// └─────────────┘    └──────┬──────┘
//                           │
//                           ▼
//                    ┌─────────────┐
//                    │  可视化展示  │
//                    └─────────────┘

PWA渐进式Web应用

PWA结合Web和原生应用优势,支持离线访问、添加到主屏幕、推送通知。Service Worker是核心,作为网络代理实现缓存策略。Workbox简化了Service Worker开发。

// Service Worker注册
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
    .then(reg => console.log('SW registered', reg))
    .catch(err => console.log('SW registration failed', err));
}

// Service Worker - sw.js
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('v1').then((cache) => {
      return cache.addAll([
        '/',
        '/styles/main.css',
        '/scripts/main.js'
      ]);
    })
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then(response => response || fetch(event.request))
  );
});

// PWA架构:
//     Web App
//        │
//        ▼
// ┌─────────────┐
// │   Service   │ ← 缓存代理
// │   Worker    │
// └──────┬──────┘
//        │
//   ┌────┼────┐
//   ▼    ▼    ▼
// Cache Network Push
//
// 缓存策略:
// 1. Cache First - 离线优先
// 2. Network First - 新鲜度优先  
// 3. Stale While Revalidate - 平衡

前端工程化是提升团队效率的关键。通过规范化的开发流程、自动化的构建部署、完善的测试覆盖,可以保证代码质量和项目稳定性。持续学习和实践是成长的唯一途径。

性能优化需要从多个维度考虑,包括网络传输、资源加载、渲染性能、运行时性能等。使用专业工具如Lighthouse、WebPageTest进行性能分析,根据数据驱动优化决策。

代码可读性和可维护性比性能更重要。清晰的命名、合理的抽象、完善的注释能让代码更容易理解和修改。遵循SOLID原则,编写高内聚低耦合的代码。

技术选型要根据项目实际情况,不要为了用新技术而用新技术。评估团队技术栈、项目规模、性能要求、维护成本等因素,选择最合适的方案。

团队协作能力同样重要。清晰的沟通、规范的代码、完善的文档能提高协作效率。Code Review是提升代码质量和知识分享的好机会。培养系统思维,从全局角度思考问题。

保持对技术的好奇心和热情,享受解决问题的过程。参与开源项目,回馈社区。关注行业动态,了解前沿技术。平衡工作与生活,持续学习与成长。

开源社区是学习的宝库。阅读优秀项目的源码可以学到最佳实践,参与开源贡献可以提升技术能力。技术之路漫长,愿我们都能成为更好的工程师。