上个月面了一家中厂,技术面第二轮,面试官笑眯眯地说:“来,手写一个 Promise。” 我脑子嗡了一下——这题我背过,但那是三年前。真要默写,肯定漏一堆边界。我看了他一眼,问:“可以用 AI 吗?” 他愣了一下,说:“你试试。” 我打开 Cursor,对着 Composer 说:“帮我实现一个符合 Promise/A+ 规范的 Promise,包含 then、catch、finally。” 三秒后代码生成。他看了两秒,说:“你过了。”

手写 Promise,面试经典老题。但 2026 年了,还有多少人在面试前夜死磕resolve、reject、then的链式调用?我不是说这东西不该学——理解原理很重要。但面试时要你一字不差默写出来,意义在哪?工作中你真的会自己写一个 Promise 吗?不会,你用原生或者蓝鸟。
这周我面了三家公司,两家允许用 AI 辅助编码,一家连 Stack Overflow 都不让开。结果呢?允许 AI 的那两家我拿到了 offer,不让的那家我连二面都没进。不是因为我不会写 Promise,而是因为他们考察的还是五年前的能力模型。
今天我就把那场面试的完整过程复盘给你:我是怎么用 Cursor 生成标准 Promise 实现的,面试官为什么认可,以及如果面试官不让你用 AI,你应该怎么回应。最后附一份可以直接复制的手写 Promise 代码(带详细注释),你拿去背也行,拿去让 AI 生成也行。
这题活了快十年了。从 ES6 诞生到现在,面前端必问。面试官想考察的点其实不是你会不会用 Promise,而是:
但问题是,这些能力真的需要默写几百行代码来验证吗? 一个能讲清楚 Promise 原理、能说对 then 的返回值为什么是新的 Promise、能解释微任务队列顺序的候选人,即使写代码时借助了 AI,他也合格了。
面试官出了题,我没有立刻敲。我说:“我平时主力工具是 Cursor,我可以用它辅助编码吗?我可以当场解释每一行代码的作用。” 他犹豫了一下,说:“那你试试,但你要讲清楚。”
我打开 Cursor 的 Composer(快捷键 Cmd+K),输入:
实现一个符合 Promise/A+ 规范的 Promise 类。要求:状态只能从 pending 变为 fulfilled 或 rejected,且不可逆;then 方法返回一个新的 Promise;支持链式调用;支持值穿透;支持异步执行;错误捕获。
三秒后,Cursor 生成了完整代码。我一行一行给面试官解释:
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
const promise2 = new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
});
} else if (this.state === 'rejected') {
queueMicrotask(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
});
} else {
this.onFulfilledCallbacks.push(() => {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
});
});
this.onRejectedCallbacks.push(() => {
queueMicrotask(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
});
});
}
});
return promise2;
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(callback) {
return this.then(
value => MyPromise.resolve(callback()).then(() => value),
reason => MyPromise.resolve(callback()).then(() => { throw reason })
);
}
static resolve(value) {
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value));
}
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let count = 0;
if (promises.length === 0) return resolve(results);
promises.forEach((p, idx) => {
MyPromise.resolve(p).then(
val => {
results[idx] = val;
count++;
if (count === promises.length) resolve(results);
},
reject
);
});
});
}
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(p => {
MyPromise.resolve(p).then(resolve, reject);
});
});
}
}
// 辅助函数:处理then返回值
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
if (x instanceof MyPromise) {
x.then(resolve, reject);
return;
}
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
let then;
try {
then = x.then;
} catch (err) {
return reject(err);
}
if (typeof then === 'function') {
let called = false;
try {
then.call(
x,
y => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
r => {
if (called) return;
called = true;
reject(r);
}
);
} catch (err) {
if (called) return;
reject(err);
}
} else {
resolve(x);
}
} else {
resolve(x);
}
}
面试官听完,问了我两个问题:
const p = new Promise((resolve) => { resolve(p); })这类死循环。我答出来了。他点了点头,没有继续问。
金句:面试官让你手写 Promise,不是要你默写 API,而是看你知不知道 “为什么要这么写”。
我把代码解释清楚后,面试官说了一句话:“你能讲明白,说明你懂原理。工具只是手段,不是目的。”
这个时代,会背代码已经不值钱了。AI 30 秒就能生成一个标准 Promise 实现。真正的能力是:
所以,如果你下次面试遇到 “手写 XXX”,大胆问:“我用 AI 辅助可以吗?我保证每一行都能解释清楚。” 大部分开明的面试官会同意,甚至会更欣赏你——因为你展示了真实的工作方式,而不是应试技巧。
也简单。你告诉他:我可以手写关键结构,但完整实现需要很多边界处理代码。要不我写核心流程,再口述其他部分?
然后你快速写出骨架:构造函数 + resolve/reject + then 的基本逻辑(省略 resolvePromise 里的细节)。面试官通常不会真让你写全,你展示出理解就够了。
千万不要硬背代码。背错了比不会更尴尬。
我统计了一下:
你在面试中愿意花 20 分钟默写,还是花 8 分钟解释原理 + 让 AI 生成?
我最终拿到了那家公司的 offer。入职后我问面试官,当时为什么同意我用 AI?他说:“因为我们团队每天都在用 Cursor。招一个不会用 AI 的人进来,反而是累赘。”
2026 年的前端面试,已经不是在考 “你会不会写”,而是在考 “你会不会用工具写”。手写 Promise 仍然是一道好题,但考核的重点已经变了。如果你还在靠死记硬背准备面试,可能会越来越吃力。
你在面试中用 AI 工具被质疑过吗?后来怎么解释的?点个赞让我看到有多少人偷偷用过。