Javascript 作用域与执行机制
作用域本质
Javascript 的作用域的本质就是词法环境(静态作用域),作用域在代码编写阶段确定的,而非执行阶段确定,这就决定了变量的查找规则是找定义时候的上层作用域,而非执行时的上层作用域
底层执行模型、上下文执行栈(ECS)和变量对象(VO/AO)
执行上下文:JS 运行时候的环境单元,分为全局执行上下文(GEC)和函数执行上下文(FEC),ECS 负责的是管理执行上下文的EC入栈和出栈的任务吧
变量对象(VO): GEC 中存储的是全局变量和函数,FEC 中就是活动对象(AO),存储函数参数,局部变量、函数声明吧
作用域链:当前的EC 的 VO 所有的上层 EC 的 VO 组成的,变量的查找规则就是沿着这个作用域链向上,一个一个的进行查找实现讷,直到到全局作用域为止吧
闭包
闭包的本质是函数执行后,其之哟用于没有被销毁,内部函数任能访问外层函数的变量
这也是作用域链持久化的一种体现吧
import { useState, useEffcet } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
useEffcet(() => {
const timer = setInterval(() => {
setCount(count + 1);
}, 1000)
return () => {
clearInterval(timer)
}
}, [count])
return <div>{count}</div>
}
this 的绑定
JS 中的 this 绑定是运行时决定的讷(除了函数),绑定的规则优先级是:new 绑定 > 显示绑定 > 隐式绑定 > 默认绑定
事件循环
JS是一个单线程的语言,核心是为了避免多线程下的操作DOM出现的冲突问题,异步能力完全依赖于事件循环来实现吧,浏览器和Nodejs 的事件循环机制存在很大的差异化,底层分别是用浏览器和libuv 库进行底层支持的讷
浏览器的事件循环
核心认为宏任务和微任务,以及宏任务队列和微任务队列的区分吧

执行的时候,先实现的是我们的没有在事件循环中的代码执行完把,这个就是同步代码把
然后检查是否含有我们的微任务队列,检查内部是否具备具体的task 需要执行,有的话就去执行该任务,队列特性是先进先出
然后就是进行对应的浏览器的渲染绘制把
最后就是执行宏任务,最后回归到主线程进行执行同步代码,依次按照上诉流程进行执行实现吧
微任务:优先级高,包括
Promise.then/catch/finally、async/await、queueMicrotask、MutationObserver;宏任务:优先级低,包括
setTimeout/setInterval、UI事件、网络请求、script标签
性能优化:利用微任务减少渲染阻塞
微任务在执行前进行渲染,避免微任务长导致渲染的卡顿出现吧
// 错误:长耗时操作放在微任务,阻塞渲染
Promise.resolve().then(() => {
let sum = 0;
for (let i = 0; i < 1e8; i++) sum += i; // 长耗时计算
console.log(sum);
});
// 优化:拆分微任务,利用requestIdleCallback
const calculate = async () => {
let sum = 0;
const chunk = 1e6;
let i = 0;
const processChunk = () => {
return new Promise(resolve => {
// 利用浏览器空闲时间执行
requestIdleCallback((deadline) => {
while (i < 1e8 && deadline.timeRemaining() > 0) {
sum += i;
i += chunk;
}
resolve();
});
});
};
while (i < 1e8) {
await processChunk();
}
console.log(sum);
};
calculate();核心的优化就是:
1. 让复杂的计算逻辑在主线程空闲的时候执行,不影响主线程的执行,也就是使用 requestIdleCallback 来使用吧
2. 让复杂的计算在子线程中执行,就是使用我们的 webworker api 来实现吧
Nodejs 事件循环
Nodejs 的事件循环和python 的 asyncio 的特性都是基于我们的 libuv 库来实现吧,核心是分为了六个阶段吧
timer 定时器阶段 --> pending callbacks 延迟回调阶段 --> idle/prepare 内部阶段 --> poll 轮询阶段 --> check(setImmediate) 阶段 --》 close callbacks 关闭回调阶段// process.nextTick不属于事件循环阶段,优先级高于所有微任务
console.log('同步代码');
setTimeout(() => {
console.log('timers阶段'); // 第二阶段
}, 0);
setImmediate(() => {
console.log('check阶段'); // 第五阶段
});
process.nextTick(() => {
console.log('process.nextTick'); // 同步代码后立即执行,优先级最高
});
Promise.resolve().then(() => {
console.log('微任务Promise'); // nextTick后,事件循环前执行
});
// 输出顺序(Node.js环境):
// 同步代码 → process.nextTick → 微任务Promise → timers阶段 → check阶段性能优化
Nodejs 的 poll 阶段依赖于底层的 libuv 的线程池,默认是4个,此时为了处理 IO DNS 操作的时候,密集型任务需要调用线程池的大小
// 在Node.js入口文件顶部设置(必须先于其他代码)
process.env.UV_THREADPOOL_SIZE = '8'; // 调整为8个线程
// 密集型文件处理案例
import fs from 'fs/promises';
async function batchReadFiles(files: string[]) {
// 并行读取,线程池扩容后效率提升
const promises = files.map(file => fs.readFile(file, 'utf8'));
const results = await Promise.all(promises);
return results;
}异步编程理解
异步编程本质:单线程 + 事件循环
JS 单线程决定了 “耗时操作必须异步”,异步的底层是:耗时操作交由浏览器 / Node.js 内核处理,完成后将回调放入任务队列,事件循环轮询执行
Promise 原理
// TS版Promise A+核心实现
type PromiseState = 'pending' | 'fulfilled' | 'rejected';
type Resolve<T> = (value: T | PromiseLike<T>) => void;
type Reject = (reason?: any) => void;
type Executor<T> = (resolve: Resolve<T>, reject: Reject) => void;
type OnFulfilled<T, R> = (value: T) => R | PromiseLike<R>;
type OnRejected<R> = (reason: any) => R | PromiseLike<R>;
class MyPromise<T> {
private state: PromiseState = 'pending';
private value: T | undefined;
private reason: any;
private onFulfilledCallbacks: Array<OnFulfilled<T, any>> = [];
private onRejectedCallbacks: Array<OnRejected<any>> = [];
constructor(executor: Executor<T>) {
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
}
private resolve(value: T | PromiseLike<T>) {
if (this.state !== 'pending') return;
// 处理Promise嵌套
if (value instanceof MyPromise) {
value.then(this.resolve.bind(this), this.reject.bind(this));
return;
}
this.state = 'fulfilled';
this.value = value;
// 执行成功回调队列
this.onFulfilledCallbacks.forEach(cb => cb(this.value!));
}
private reject(reason?: any) {
if (this.state !== 'pending') return;
this.state = 'rejected';
this.reason = reason;
// 执行失败回调队列
this.onRejectedCallbacks.forEach(cb => cb(this.reason));
}
then<R1 = T, R2 = never>(
onFulfilled?: OnFulfilled<T, R1>,
onRejected?: OnRejected<R2>
): MyPromise<R1 | R2> {
onFulfilled = onFulfilled || ((v) => v as R1);
onRejected = onRejected || ((r) => { throw r; });
return new MyPromise((resolve, reject) => {
// 状态已完成,异步执行回调(符合A+规范)
if (this.state === 'fulfilled') {
queueMicrotask(() => {
try {
const result = onFulfilled!(this.value!);
resolve(result);
} catch (e) {
reject(e);
}
});
}
if (this.state === 'rejected') {
queueMicrotask(() => {
try {
const result = onRejected!(this.reason);
resolve(result);
} catch (e) {
reject(e);
}
});
}
// 状态pending,存入回调队列
if (this.state === 'pending') {
this.onFulfilledCallbacks.push((value) => {
try {
const result = onFulfilled!(value);
resolve(result);
} catch (e) {
reject(e);
}
});
this.onRejectedCallbacks.push((reason) => {
try {
const result = onRejected!(reason);
resolve(result);
} catch (e) {
reject(e);
}
});
}
});
}
catch<R = never>(onRejected?: OnRejected<R>): MyPromise<T | R> {
return this.then(undefined, onRejected);
}
finally(onFinally?: () => void): MyPromise<T> {
return this.then(
(value) => {
onFinally?.();
return value;
},
(reason) => {
onFinally?.();
throw reason;
}
);
}
}
// 测试案例
new MyPromise<number>((resolve) => {
setTimeout(() => resolve(10), 100);
})
.then(v => v * 2)
.then(v => console.log(v)) // 输出20
.catch(e => console.error(e));Async/Await
本质就是Generator + 自动执行器的语法糖吧
// TS案例:手动实现async/await的自动执行器
function myAsync<T>(generator: Generator): Promise<T> {
return new Promise((resolve, reject) => {
const next = (result: any) => {
let res;
try {
res = generator.next(result);
} catch (e) {
return reject(e);
}
if (res.done) {
return resolve(res.value);
}
// 将yield后的Promise转为thenable
Promise.resolve(res.value).then(next, (err) => generator.throw(err));
};
next(undefined);
});
}
// 使用自定义执行器
function* gen() {
const res1 = yield fetch('https://api.example.com/data1');
const data1 = yield res1.json();
const res2 = yield fetch(`https://api.example.com/data2?id=${data1.id}`);
const data2 = yield res2.json();
return data2;
}
// 等价于async/await
myAsync(gen()).then(data => console.log(data)).catch(e => console.error(e));
// 原生async/await版本(语法糖)
async function fetchData() {
const res1 = await fetch('https://api.example.com/data1');
const data1 = await res1.json();
const res2 = await fetch(`https://api.example.com/data2?id=${data1.id}`);
const data2 = await res2.json();
return data2;
}前端工程化
模块化规范

打包工具
webpack

// webpack.config.ts(TS版配置)
import path from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import TerserPlugin from 'terser-webpack-plugin';
import CompressionPlugin from 'compression-webpack-plugin';
export default {
entry: './src/index.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js', // 内容哈希,强缓存
clean: true,
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
alias: {
// 路径别名,减少解析耗时
'@': path.resolve(__dirname, 'src'),
},
},
module: {
rules: [
{
test: /\.(ts|tsx)$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
optimization: {
minimizer: [
new TerserPlugin({
// 压缩优化:删除注释、简化变量名
terserOptions: {
compress: { drop_console: process.env.NODE_ENV === 'production' },
},
}),
],
splitChunks: {
// 代码分割:抽离公共模块、第三方库
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
runtimeChunk: 'single', // 抽离运行时代码,避免缓存失效
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
minify: process.env.NODE_ENV === 'production',
}),
new CompressionPlugin({
// 生成gzip压缩包,减少传输体积
algorithm: 'gzip',
test: /\.(js|css|html|svg)$/,
threshold: 8192,
}),
],
mode: process.env.NODE_ENV || 'development',
devtool: process.env.NODE_ENV === 'production' ? 'source-map' : 'inline-source-map',
};vite
原生 esmodule + 按需编译支持
按需打包,性能更强
// vite.config.ts(React+TS配置)
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc'; // SWC替代Babel,编译更快
import path from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
build: {
rollupOptions: {
// 生产环境代码分割
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
},
},
},
minify: 'esbuild', // ESBuild压缩,比Terser快
},
server: {
open: true,
port: 3000,
},
});包管理工具

浏览器核心原理:渲染+v8+多进程架构
浏览器渲染原理

核心需要优化的点是
减少回流(reflow)和重绘(repaint)
回流:布局变化,代价高(如修改 width/height/position);
重绘:样式变化(不影响布局),代价低(如修改 color/background);
合成:仅修改图层位置,代价最低(如 transform/opacity)
import { useState, useRef, useEffect } from 'react';
// 错误:频繁修改width导致回流
const BadComponent = () => {
const [width, setWidth] = useState(100);
useEffect(() => {
const timer = setInterval(() => {
setWidth(w => w + 1); // 每次修改触发回流
}, 16);
return () => clearInterval(timer);
}, []);
return <div style={{ width: `${width}px`, height: '100px' }}>Bad</div>;
};
// 优化:使用transform(仅触发合成)
const GoodComponent = () => {
const [scale, setScale] = useState(1);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const timer = setInterval(() => {
setScale(s => s + 0.01); // transform仅触发合成
}, 16);
return () => clearInterval(timer);
}, []);
return (
<div
ref={ref}
style={{
width: '100px',
height: '100px',
transform: `scale(${scale})`,
willChange: 'transform', // 告诉浏览器提前优化
}}
>
Good
</div>
);
};V8 引擎
V8 引擎是浏览器和nodejs 的核心吧
解析器(Ignition) --> 字节码 --> 编译器(TurboFan) --》 机器码Ignition:生成字节码(比机器码小,跨平台),解释执行;
TurboFan:对热点代码(频繁执行)编译为机器码,提升性能;
垃圾回收(GC):分代回收(新生代 Scavenge 算法,老生代 Mark-Sweep/Mark-Compact)
// 错误:每次循环创建新对象
function badLoop() {
const arr = [];
for (let i = 0; i < 1e6; i++) {
arr.push({ value: i }); // 临时对象频繁创建
}
}
// 优化:复用对象
function goodLoop() {
const arr = [];
const temp = { value: 0 }; // 复用对象
for (let i = 0; i < 1e6; i++) {
temp.value = i;
arr.push(temp);
}
}浏览器过进程和多线程结构

浏览器主进程:负责窗口管理、进程调度;
渲染进程:每个标签页一个,沙箱隔离,包含 JS 线程 / 渲染线程(互斥);
GPU 进程:负责 3D 渲染、合成图层;
进程间通信(IPC):所有进程通过主进程通信,保证安全
react concurrent mode 关联
React 的 Concurrent Mode(并发模式)利用浏览器的 “时间切片”,将长任务拆分为小任务,在 JS 线程空闲时执行,避免阻塞渲染线程
import { createRoot } from 'react-dom/client';
import App from './App';
// 启用Concurrent Mode(React 18+)
const root = createRoot(document.getElementById('root')!);
root.render(<App />);
// 组件中使用useDeferredValue延迟渲染
import { useState, useDeferredValue } from 'react';
const SearchComponent = () => {
const [query, setQuery] = useState('');
// 延迟更新query,优先保证输入响应
const deferredQuery = useDeferredValue(query, { timeoutMs: 200 });
return (
<div>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="搜索..."
/>
{/* 耗时的搜索结果渲染,使用延迟值 */}
<SearchResults query={deferredQuery} />
</div>
);
};Nodejs 底层扩展
libuv
是 nodejs 的跨平台异步 IO 库
事件循环实现;
线程池(处理文件 I/O、DNS、加密等);
跨平台 API(统一 Windows/Linux/macOS 的 I/O 接口)
利用 libuv 处理密集型任务
// Node.js+TS案例:调整线程池处理图片压缩
import sharp from 'sharp'; // 底层使用libuv线程池
import fs from 'fs/promises';
// 提前设置线程池大小
process.env.UV_THREADPOOL_SIZE = '8';
async function batchCompressImages(inputDir: string, outputDir: string) {
const files = await fs.readdir(inputDir);
const imageFiles = files.filter(file => /\.(jpg|png)$/.test(file));
// 并行压缩,线程池扩容后效率提升
const promises = imageFiles.map(async (file) => {
const inputPath = `${inputDir}/${file}`;
const outputPath = `${outputDir}/${file}`;
// sharp底层使用libuv线程池,非JS主线程
await sharp(inputPath).resize(800, 600).toFile(outputPath);
});
await Promise.all(promises);
console.log('压缩完成');
}Native Addons
Native Addons 是用 C++/Rust 编写的 Node.js 扩展,用于处理 JS 不擅长的 “计算密集型任务”(如加密、图形处理)
CPP 编写 Nodejs 扩展(N-API)
// addon.cc(C++扩展)
#include <napi.h>
#include <cmath>
// 计算密集型任务:质数判断
bool isPrime(int n) {
if (n <= 1) return false;
if (n == 2) return true;
if (n % 2 == 0) return false;
for (int i = 3; i <= sqrt(n); i += 2) {
if (n % i == 0) return false;
}
return true;
}
// N-API包装函数
Napi::Boolean IsPrime(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() < 1 || !info[0].IsNumber()) {
Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException();
return Napi::Boolean::New(env, false);
}
int n = info[0].As<Napi::Number>().Int32Value();
return Napi::Boolean::New(env, isPrime(n));
}
// 初始化扩展
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "isPrime"), Napi::Function::New(env, IsPrime));
return exports;
}
NODE_API_MODULE(addon, Init)// index.ts(Node.js调用C++扩展)
import { readFileSync } from 'fs';
import { join } from 'path';
import { load } from 'node-gyp-build';
// 加载编译后的扩展
const addon = load(join(__dirname, '.'));
// 测试:JS vs C++性能对比
function jsIsPrime(n: number): boolean {
if (n <= 1) return false;
if (n === 2) return true;
if (n % 2 === 0) return false;
for (let i = 3; i <= Math.sqrt(n); i += 2) {
if (n % i === 0) return false;
}
return true;
}
// 测试1000003(大质数)
const n = 1000003;
console.time('JS');
console.log(jsIsPrime(n)); // true
console.timeEnd('JS'); // ~10ms
console.time('C++');
console.log(addon.isPrime(n)); // true
console.timeEnd('C++'); // ~0.1ms(性能提升100倍)Rust 编写Nodejs 扩展(Neon)
// src/lib.rs(Rust扩展)
use neon::prelude::*;
// 质数判断
fn is_prime(n: i32) -> bool {
if n <= 1 {
return false;
}
if n == 2 {
return true;
}
if n % 2 == 0 {
return false;
}
(3..=((n as f64).sqrt() as i32))
.step_by(2)
.all(|i| n % i != 0)
}
// Neon包装函数
fn is_prime_js(mut cx: FunctionContext) -> JsResult<JsBoolean> {
let n = cx.argument::<JsNumber>(0)?.value(&mut cx) as i32;
Ok(cx.boolean(is_prime(n)))
}
// 初始化扩展
#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
cx.export_function("isPrime", is_prime_js)?;
Ok(())
}// index.ts(Node.js调用Rust扩展)
import { isPrime } from './native/index';
// 性能测试(Rust vs C++接近,内存更安全)
const n = 1000003;
console.time('Rust');
console.log(isPrime(n)); // true
console.timeEnd('Rust'); // ~0.1mswasm 跨语言执行
Wasm 是二进制指令集,可将 C++/Rust 编译为 Wasm,在浏览器 / Node.js 中执行,性能接近原生
// src/lib.rs(Rust编写Wasm)
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn calculate_fib(n: u32) -> u64 {
if n <= 1 {
return n as u64;
}
let mut a = 0;
let mut b = 1;
for _ in 2..=n {
let c = a + b;
a = b;
b = c;
}
b
}// fib.wasm.d.ts(TS类型声明)
declare module './fib.wasm' {
export function calculate_fib(n: number): number;
export function default(): {
calculate_fib: (n: number) => number;
};
}// FibComponent.tsx(React+TS调用Wasm)
import { useState, useEffect } from 'react';
import init, { calculate_fib } from './fib.wasm';
const FibComponent = () => {
const [result, setResult] = useState<number | null>(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
// 初始化Wasm
init().then(() => console.log('Wasm loaded'));
}, []);
const handleCalculate = (n: number) => {
setLoading(true);
// Wasm执行斐波那契(比JS快10倍+)
const start = performance.now();
const res = calculate_fib(n);
const end = performance.now();
setResult(res);
setLoading(false);
console.log(`耗时:${end - start}ms`);
};
return (
<div>
<button onClick={() => handleCalculate(100000)} disabled={loading}>
计算斐波那契第100000项
</button>
{result && <div>结果:{result}</div>}
</div>
);
};
export default FibComponent;JS 深度原理
原型和原型链
JS 的继承基于原型链,React 类组件的extends React.Component本质是原型链继承
// 简化版React.Component
class Component {
props: any;
state: any;
constructor(props: any) {
this.props = props;
this.state = {};
}
setState(partialState: any) {
this.state = { ...this.state, ...partialState };
// 触发重新渲染(简化版)
this.render();
}
render() {}
}
// 自定义组件继承Component(原型链)
class MyComponent extends Component {
constructor(props: any) {
super(props);
this.state = { count: 0 };
}
render() {
return <div>{this.state.count}</div>;
}
}
// 原型链验证
console.log(MyComponent.prototype.__proto__ === Component.prototype); // trueReact Fiber 架构
事件循环深度结合起来的讷
React Fiber 是为了解决 “长任务阻塞渲染” 的问题,核心是
将虚拟 DOM 的 diff 过程拆分为 “小任务”;
利用
requestIdleCallback在浏览器空闲时执行任务;支持任务暂停 / 恢复,优先处理高优先级任务(如用户输入)
// 简化版Fiber调度
type Fiber = {
type: string;
props: any;
child: Fiber | null;
sibling: Fiber | null;
alternate: Fiber | null;
};
function scheduleWork(fiber: Fiber) {
// 利用requestIdleCallback调度任务
requestIdleCallback((deadline) => {
workLoop(deadline, fiber);
});
}
function workLoop(deadline: IdleDeadline, fiber: Fiber | null) {
let shouldYield = false;
while (fiber && !shouldYield) {
// 处理当前Fiber节点
fiber = performUnitOfWork(fiber);
// 检查是否需要暂停(浏览器需要渲染)
shouldYield = deadline.timeRemaining() < 1;
}
// 未完成,继续调度
if (fiber) {
scheduleWork(fiber);
}
}
function performUnitOfWork(fiber: Fiber): Fiber | null {
// 简化版:创建子Fiber
if (fiber.type === 'div') {
fiber.child = { type: 'span', props: {}, child: null, sibling: null, alternate: null };
}
// 返回下一个任务(子节点优先,然后兄弟节点)
return fiber.child || fiber.sibling;
}