JavaScript优化

JavaScript代码的执行效率直接影响应用的性能。本章将深入探讨JavaScript代码层面的优化技术,包括算法优化、内存管理、V8引擎优化等。

代码执行效率

算法复杂度优化

const algorithmOptimization = {
    bad: {
        description: 'O(n²) 嵌套循环',
        code: `
            function findDuplicates(arr) {
                const duplicates = [];
                for (let i = 0; i < arr.length; i++) {
                    for (let j = i + 1; j < arr.length; j++) {
                        if (arr[i] === arr[j] && !duplicates.includes(arr[i])) {
                            duplicates.push(arr[i]);
                        }
                    }
                }
                return duplicates;
            }
        `,
        complexity: 'O(n²) 或更差'
    },
    
    good: {
        description: 'O(n) 使用Map',
        code: `
            function findDuplicates(arr) {
                const seen = new Map();
                const duplicates = new Set();
                
                for (const item of arr) {
                    if (seen.has(item)) {
                        duplicates.add(item);
                    } else {
                        seen.set(item, true);
                    }
                }
                
                return [...duplicates];
            }
        `,
        complexity: 'O(n)'
    }
};

循环优化

const loopOptimization = {
    cacheLength: `
        function processArray(arr) {
            const len = arr.length;
            for (let i = 0; i < len; i++) {
                arr[i] = arr[i] * 2;
            }
        }
    `,
    
    reverseLoop: `
        function processArrayReverse(arr) {
            let i = arr.length;
            while (i--) {
                arr[i] = arr[i] * 2;
            }
        }
    `,
    
    forOf: `
        function processArrayForOf(arr) {
            for (const item of arr) {
                console.log(item);
            }
        }
    `,
    
    avoidInLoop: `
        const arr = [1, 2, 3, 4, 5];
        
        for (let i = 0; i < arr.length; i++) {
            if (arr[i] in obj) {
            }
        }
        
        const hasOwn = Object.prototype.hasOwnProperty;
        for (let i = 0; i < arr.length; i++) {
            if (hasOwn.call(obj, arr[i])) {
            }
        }
    `
};

条件判断优化

const conditionOptimization = {
    switchVsObject: `
        function getStatusText(status) {
            switch (status) {
                case 0: return '待处理';
                case 1: return '处理中';
                case 2: return '已完成';
                case 3: return '已取消';
                default: return '未知';
            }
        }
        
        const statusMap = {
            0: '待处理',
            1: '处理中',
            2: '已完成',
            3: '已取消'
        };
        
        function getStatusTextOptimized(status) {
            return statusMap[status] ?? '未知';
        }
    `,
    
    earlyReturn: `
        function validate(user) {
            if (!user) {
                return { valid: false, error: '用户不存在' };
            }
            
            if (!user.name) {
                return { valid: false, error: '姓名不能为空' };
            }
            
            if (!user.email) {
                return { valid: false, error: '邮箱不能为空' };
            }
            
            if (!user.age || user.age < 0) {
                return { valid: false, error: '年龄无效' };
            }
            
            return { valid: true };
        }
    `,
    
    guardClauses: `
        function processPayment(amount, user) {
            if (!user.isAuthenticated) {
                throw new Error('用户未认证');
            }
            
            if (amount <= 0) {
                throw new Error('金额必须大于0');
            }
            
            if (!user.hasPaymentMethod) {
                throw new Error('未添加支付方式');
            }
            
            return processTransaction(amount, user);
        }
    `
};

内存管理优化

对象创建优化

class Vector {
    constructor(x = 0, y = 0, z = 0) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    
    add(v) {
        this.x += v.x;
        this.y += v.y;
        this.z += v.z;
        return this;
    }
    
    clone() {
        return new Vector(this.x, this.y, this.z);
    }
}

const v1 = new Vector(1, 2, 3);
const v2 = new Vector(4, 5, 6);
v1.add(v2);

function createVector(x, y, z) {
    return { x, y, z };
}

function addVectors(a, b, out) {
    out.x = a.x + b.x;
    out.y = a.y + b.y;
    out.z = a.z + b.z;
    return out;
}

const temp = createVector(0, 0, 0);
addVectors(v1, v2, temp);

避免内存泄漏

class EventManager {
    constructor() {
        this.events = new Map();
        this.boundHandlers = new WeakMap();
    }
    
    on(element, event, handler) {
        const boundHandler = handler.bind(this);
        this.boundHandlers.set(handler, boundHandler);
        
        element.addEventListener(event, boundHandler);
        
        if (!this.events.has(element)) {
            this.events.set(element, new Map());
        }
        this.events.get(element).set(event, boundHandler);
    }
    
    off(element, event, handler) {
        const boundHandler = this.boundHandlers.get(handler);
        if (boundHandler) {
            element.removeEventListener(event, boundHandler);
            this.events.get(element)?.delete(event);
        }
    }
    
    destroy() {
        for (const [element, events] of this.events) {
            for (const [event, handler] of events) {
                element.removeEventListener(event, handler);
            }
        }
        this.events.clear();
    }
}

class Component {
    constructor() {
        this.data = [];
        this.timer = null;
        this.eventManager = new EventManager();
    }
    
    start() {
        this.timer = setInterval(() => {
            this.update();
        }, 1000);
    }
    
    update() {
        this.data.push(Date.now());
        
        if (this.data.length > 100) {
            this.data = this.data.slice(-50);
        }
    }
    
    destroy() {
        if (this.timer) {
            clearInterval(this.timer);
            this.timer = null;
        }
        this.eventManager.destroy();
        this.data = [];
    }
}

使用WeakMap和WeakSet

const privateData = new WeakMap();

class SecretHolder {
    constructor(secret) {
        privateData.set(this, { secret });
    }
    
    getSecret() {
        return privateData.get(this)?.secret;
    }
    
    setSecret(secret) {
        privateData.get(this).secret = secret;
    }
}

const holder = new SecretHolder('my secret');
console.log(holder.getSecret());

const cache = new WeakMap();

function getCachedData(obj) {
    if (cache.has(obj)) {
        return cache.get(obj);
    }
    
    const data = expensiveComputation(obj);
    cache.set(obj, data);
    return data;
}

V8引擎优化

隐藏类(Hidden Classes)

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

const p1 = new Point(1, 2);
const p2 = new Point(3, 4);

const p3 = new Point(5, 6);
p3.z = 7;

function createPoint(x, y) {
    return { x, y };
}

const p4 = createPoint(1, 2);
const p5 = createPoint(3, 4);

内联缓存(Inline Caches)

function getX(point) {
    return point.x;
}

const p1 = { x: 1, y: 2 };
const p2 = { x: 3, y: 4 };

for (let i = 0; i < 10000; i++) {
    getX(p1);
    getX(p2);
}

const p3 = { x: 5, y: 6, z: 7 };
getX(p3);

优化建议

const v8Optimization = {
    monomorphic: `
        function process(obj) {
            return obj.value;
        }
        
        const obj = { value: 1 };
        for (let i = 0; i < 10000; i++) {
            process(obj);
        }
    `,
    
    polymorphic: `
        function process(obj) {
            return obj.value;
        }
        
        for (let i = 0; i < 10000; i++) {
            const obj = i % 2 === 0 
                ? { value: 1 } 
                : { value: 2, extra: true };
            process(obj);
        }
    `,
    
    megamorphic: `
        function process(obj) {
            return obj.value;
        }
        
        for (let i = 0; i < 10000; i++) {
            const obj = { value: i };
            for (let j = 0; j < i % 10; j++) {
                obj['prop' + j] = j;
            }
            process(obj);
        }
    `
};

避免优化陷阱

const optimizationTraps = {
    avoidTryCatch: `
        function withTryCatch(arr) {
            const result = [];
            for (let i = 0; i < arr.length; i++) {
                try {
                    result.push(arr[i] * 2);
                } catch (e) {
                    result.push(0);
                }
            }
            return result;
        }
        
        function withoutTryCatch(arr) {
            const result = [];
            for (let i = 0; i < arr.length; i++) {
                result.push(arr[i] * 2);
            }
            return result;
        }
    `,
    
    avoidArguments: `
        function bad(a, b) {
            arguments[0] = 10;
            return a + b;
        }
        
        function good(a, b) {
            'use strict';
            return a + b;
        }
    `,
    
    avoidDelete: `
        const obj = { a: 1, b: 2, c: 3 };
        delete obj.b;
        
        const obj2 = { a: 1, b: 2, c: 3 };
        obj2.b = undefined;
    `
};

函数优化

函数内联

function square(x) {
    return x * x;
}

function sumOfSquares(a, b) {
    return square(a) + square(b);
}

function sumOfSquaresInlined(a, b) {
    return a * a + b * b;
}

柯里化与偏函数

function curry(fn) {
    return function curried(...args) {
        if (args.length >= fn.length) {
            return fn.apply(this, args);
        }
        return (...moreArgs) => curried.apply(this, [...args, ...moreArgs]);
    };
}

function add(a, b, c) {
    return a + b + c;
}

const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3));
console.log(curriedAdd(1, 2)(3));
console.log(curriedAdd(1)(2, 3));

function partial(fn, ...presetArgs) {
    return (...laterArgs) => fn(...presetArgs, ...laterArgs);
}

const add5 = partial(add, 2, 3);
console.log(add5(10));

函数记忆化

function memoize(fn) {
    const cache = new Map();
    
    return function(...args) {
        const key = JSON.stringify(args);
        
        if (cache.has(key)) {
            return cache.get(key);
        }
        
        const result = fn.apply(this, args);
        cache.set(key, result);
        return result;
    };
}

const fibonacci = memoize(function(n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
});

console.log(fibonacci(50));

function memoizeWithLimit(fn, limit = 100) {
    const cache = new Map();
    const keys = [];
    
    return function(...args) {
        const key = JSON.stringify(args);
        
        if (cache.has(key)) {
            return cache.get(key);
        }
        
        const result = fn.apply(this, args);
        cache.set(key, result);
        keys.push(key);
        
        if (keys.length > limit) {
            const oldestKey = keys.shift();
            cache.delete(oldestKey);
        }
        
        return result;
    };
}

数据结构优化

选择合适的数据结构

const dataStructureChoice = {
    array: {
        use: '有序数据、需要索引访问',
        operations: {
            access: 'O(1)',
            search: 'O(n)',
            insert: 'O(n)',
            delete: 'O(n)'
        }
    },
    
    object: {
        use: '键值对存储、属性访问',
        operations: {
            access: 'O(1)',
            search: 'O(n)',
            insert: 'O(1)',
            delete: 'O(1)'
        }
    },
    
    map: {
        use: '需要非字符串键、频繁增删',
        operations: {
            access: 'O(1)',
            search: 'O(1)',
            insert: 'O(1)',
            delete: 'O(1)'
        }
    },
    
    set: {
        use: '唯一值集合、快速查找',
        operations: {
            has: 'O(1)',
            add: 'O(1)',
            delete: 'O(1)'
        }
    }
};

function benchmark() {
    const size = 100000;
    const arr = Array.from({ length: size }, (_, i) => i);
    const set = new Set(arr);
    const obj = Object.fromEntries(arr.map(i => [i, i]));
    const map = new Map(arr.map(i => [i, i]));
    
    const target = size - 1;
    
    console.time('Array.includes');
    arr.includes(target);
    console.timeEnd('Array.includes');
    
    console.time('Set.has');
    set.has(target);
    console.timeEnd('Set.has');
    
    console.time('Object.hasOwn');
    Object.hasOwn(obj, target);
    console.timeEnd('Object.hasOwn');
    
    console.time('Map.has');
    map.has(target);
    console.timeEnd('Map.has');
}

数组操作优化

const arrayOptimization = {
    pushVsConcat: `
        const arr1 = [1, 2, 3];
        const arr2 = [4, 5, 6];
        
        arr1.push(...arr2);
        
        const arr3 = arr1.concat(arr2);
    `,
    
    filterMapChain: `
        const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        
        const result1 = data
            .filter(x => x % 2 === 0)
            .map(x => x * 2);
        
        const result2 = data.reduce((acc, x) => {
            if (x % 2 === 0) {
                acc.push(x * 2);
            }
            return acc;
        }, []);
    `,
    
    flatMap: `
        const nested = [[1, 2], [3, 4], [5, 6]];
        
        const result1 = nested.flat().map(x => x * 2);
        
        const result2 = nested.flatMap(arr => arr.map(x => x * 2));
    `,
    
    spreadVsSlice: `
        const arr = [1, 2, 3, 4, 5];
        
        const copy1 = [...arr];
        
        const copy2 = arr.slice();
    `
};

异步性能优化

并行执行

async function parallelExecution() {
    const urls = ['/api/1', '/api/2', '/api/3', '/api/4', '/api/5'];
    
    console.time('串行');
    const results1 = [];
    for (const url of urls) {
        results1.push(await fetch(url).then(r => r.json()));
    }
    console.timeEnd('串行');
    
    console.time('并行');
    const results2 = await Promise.all(
        urls.map(url => fetch(url).then(r => r.json()))
    );
    console.timeEnd('并行');
}

async function parallelWithLimit(tasks, limit = 3) {
    const results = [];
    const executing = new Set();
    
    for (const task of tasks) {
        const promise = Promise.resolve().then(() => task());
        results.push(promise);
        executing.add(promise);
        
        const cleanup = () => executing.delete(promise);
        promise.then(cleanup, cleanup);
        
        if (executing.size >= limit) {
            await Promise.race(executing);
        }
    }
    
    return Promise.all(results);
}

任务调度

class TaskScheduler {
    constructor(concurrency = 4) {
        this.concurrency = concurrency;
        this.running = 0;
        this.queue = [];
    }
    
    async run(task) {
        return new Promise((resolve, reject) => {
            const execute = async () => {
                this.running++;
                try {
                    const result = await task();
                    resolve(result);
                } catch (error) {
                    reject(error);
                } finally {
                    this.running--;
                    this.next();
                }
            };
            
            if (this.running < this.concurrency) {
                execute();
            } else {
                this.queue.push(execute);
            }
        });
    }
    
    next() {
        if (this.queue.length > 0 && this.running < this.concurrency) {
            const next = this.queue.shift();
            next();
        }
    }
}

const scheduler = new TaskScheduler(3);

const tasks = Array.from({ length: 10 }, (_, i) => 
    () => new Promise(resolve => {
        console.log(`任务 ${i} 开始`);
        setTimeout(() => {
            console.log(`任务 ${i} 完成`);
            resolve(i);
        }, 1000);
    })
);

tasks.forEach(task => scheduler.run(task));

性能分析工具

使用console.time

function measurePerformance() {
    console.time('数据处理');
    
    const data = Array.from({ length: 1000000 }, (_, i) => i);
    const result = data.filter(x => x % 2 === 0).map(x => x * 2);
    
    console.timeEnd('数据处理');
    
    console.time('优化版本');
    
    const result2 = [];
    for (let i = 0; i < 1000000; i++) {
        if (i % 2 === 0) {
            result2.push(i * 2);
        }
    }
    
    console.timeEnd('优化版本');
}

自定义性能分析器

class Profiler {
    constructor() {
        this.profiles = new Map();
    }
    
    start(name) {
        this.profiles.set(name, {
            startTime: performance.now(),
            startMemory: performance.memory?.usedJSHeapSize
        });
    }
    
    end(name) {
        const profile = this.profiles.get(name);
        if (!profile) return null;
        
        const endTime = performance.now();
        const endMemory = performance.memory?.usedJSHeapSize;
        
        const result = {
            duration: endTime - profile.startTime,
            memoryDelta: endMemory && profile.startMemory
                ? endMemory - profile.startMemory
                : null
        };
        
        this.profiles.delete(name);
        return result;
    }
    
    async profile(name, fn) {
        this.start(name);
        const result = await fn();
        const stats = this.end(name);
        
        console.log(`[${name}] 耗时: ${stats.duration.toFixed(2)}ms`);
        if (stats.memoryDelta) {
            console.log(`[${name}] 内存变化: ${(stats.memoryDelta / 1024).toFixed(2)}KB`);
        }
        
        return { result, stats };
    }
}

const profiler = new Profiler();

profiler.profile('数组操作', () => {
    const arr = Array.from({ length: 1000000 }, (_, i) => i);
    return arr.filter(x => x % 2 === 0);
});

东巴文小贴士

🚀 V8优化要点

  1. 保持对象结构一致:相同构造函数创建的对象应有相同属性
  2. 避免在热代码中使用try-catch:会阻止优化
  3. 使用monomorphic操作:保持函数参数类型一致
  4. 合理使用内置方法:V8对内置方法有深度优化

💡 性能优化检查清单

  • 是否选择了正确的数据结构?
  • 循环中是否有不必要的计算?
  • 是否避免了内存泄漏?
  • 异步操作是否并行执行?
  • 是否有性能监控机制?

下一步

下一章将探讨 创建型模式,学习设计模式在JavaScript中的应用,从创建对象的各种模式开始。