首页 / 中文教程 / 教程

用麦当劳点餐理解 JavaScript Promise(订单承诺类比)

作者把这个类比改了一点、补充了更多细节,然后让 AI 补全。下面是最终成品——用麦当劳点餐来理解 Promise:

Ray Chan·2026-08-12·约 3 分钟

这篇文章最初是作者在学习 JavaScript 课程时的笔记。

先看课程里的原版类比:

Promise 就像在餐厅点餐:你会拿到一张小票(Promise 对象),表示你的订单正在处理中。订单要么成功送达(resolved,已兑现),要么被取消(rejected,已拒绝),你可以挂上处理动作(.then().catch())来应对这两种结果。

作者把这个类比改了一点、补充了更多细节,然后让 AI 补全。下面是最终成品——用麦当劳点餐来理解 Promise

  1. 在麦当劳下单,拿到一个叫号器(buzzer)。

    • 这就是创建一个新的 Promise——它代表一个未来的值。
    • 叫号器(Promise)此刻处于 pending(等待中) 状态。
  2. 等待备餐在后台进行。

    • 这是一个异步操作,就像 setTimeout() 或一次 API 调用。
    • 后厨员工(JavaScript 引擎)在帮你做餐,同时不阻塞其他顾客(其他代码照常运行)。
  3. 餐做好时,店员按下按钮,你的叫号器响了。

    • 这是 Promise 状态变为 fulfilled(已兑现)
    • 处理异步操作的代码调用了 resolve() 函数。
  4. 做好的餐在你回到柜台时递给你。

    • 这就是 Promise 兑现时携带的数据
    • 传给 resolve() 的值可以在 .then() 处理函数里拿到。
  5. 如果薯条卖完了或者订单出了问题,经理会过来跟你解释。

    • 这是 Promise 状态变为 rejected(已拒绝)
    • reject() 函数被调用,并携带一个错误原因。
  6. 对问题的解释(比如「薯条卖完了」)就是错误信息。

    • 这是 Promise 拒绝时携带的错误数据
    • 传给 reject() 的值可以在 .catch() 处理函数里拿到。
  7. 你决定下一步怎么办——拿到餐,或者听完问题后换别的。

    • 这就是你的代码在 .then().catch() 处理函数里执行。
    • 你可能满意地享用,也可能改点别的。
  8. 当你拿到餐或处理完问题后,你与这个订单的交互就结束了。

    • Promise 现在处于 settled(已定型) 状态(fulfilled 或 rejected 二选一)。
    • Promise 一旦定型,状态就再也不能改变。

这个类比覆盖了 Promise 的全部三种状态:

  • Pending(等待中):已下单,等餐。
  • Fulfilled(已兑现):餐做好并交付。
  • Rejected(已拒绝):订单因问题无法完成。

代码形式

const orderFood = menuItem => {
	return new Promise((resolve, reject) => {
		console.log(`Order for ${menuItem} received. Please wait...`);

		// Simulate food preparation (async operation)
		setTimeout(() => {
			// Randomly succeed or fail the order
			if (Math.random() > 0.2) {
				// Food prepared successfully
				const food = `🍔 Fresh ${menuItem}`;
				resolve(food); // Promise fulfilled
			} else {
				// Something went wrong
				reject(`Sorry, we're out of ${menuItem}`); // Promise rejected
			}
		}, 2000);
	});
};

// Using the Promise
orderFood('fries')
	.then(food => {
		console.log(`Enjoy your ${food}!`);
	})
	.catch(problem => {
		console.log(`Order failed: ${problem}`);
	})
	.finally(() => {
		console.log("Thank you for visiting McDonald's");
	});

执行流程拆解

  1. 调用 orderFood('fries') 时:

    • 函数立即执行。
    • 创建了一个新的 Promise 对象。
    • executor 函数(传给 Promise 构造器的那个函数)同步运行。
  2. 在 executor 函数内部:

    • console.log(...) 立即执行。
    • 调用 setTimeout(),把回调安排到稍后运行。
    • Promise 对象返回给调用方(仍处于 pending 状态)。
  3. Promise 返回之后:

    • .then().catch() 处理函数挂到 Promise 上。
    • 这些处理函数此刻不会执行——它们只是注册好,等稍后运行。
  4. 定时器完成时(2000ms 后):

    • 定时器回调执行。
    • resolve()reject() 被调用。
    • Promise 状态变为 fulfilled 或 rejected。
    • 对应的处理函数(.then().catch())被排进下一个事件循环迭代执行。

译者注:原文此处有两张示意图(Promise 兑现时 / Promise 拒绝时的控制台输出),爬取时未抓取到图片。

附记:resolve 和 reject 到底是什么?

作者最困惑的一点:resolvereject 这两个函数是哪来的?定义在哪里?

笔记:

resolvereject 只是我们给这两个参数起的常用名字,跟任何函数的参数一样,叫别的名字也行。

这两个函数是 JavaScript 引擎在你创建新 Promise 时提供的——更准确地说,是 Promise 类的 constructor() 提供的。它们会被自动传给 executor 函数(你传给 Promise 构造器的那个函数)。

Promise 构造器的签名长这样:

new Promise(executor);

其中 executor 是这样一个函数:

function executor(resolveFunction, rejectFunction) {
    // Your code here
}

resolvereject 是 JavaScript 引擎提供的内部函数。虽然你看不到它们的真实实现,但概念上 resolve 函数会:

  • 把 Promise 的状态从 “pending” 改为 “fulfilled”;
  • 把传给它的值设为 Promise 的结果值;
  • 安排所有挂着的 .then() 回调在下一个事件循环迭代执行。

另一个例子

Promise 构造器会给 executor 函数提供两个参数。用其中一个(当作 resolve)还是两个都用(resolvereject),由你自己决定。

const wait = milliseconds => {
    return new Promise((resolve, reject) => {
        // Validate input
        if (typeof milliseconds !== 'number' || milliseconds < 0) {
            reject(new Error('milliseconds must be a positive number'));
            return;
        }
        
        // Set up the timer
        setTimeout(() => {
            resolve('Timer completed!'); // Can pass a value
        }, milliseconds);
    });
}

// Usage
wait(1000)
    .then(message => console.log(message)) // "Timer completed!"
    .catch(error => console.error(error));

可以给 resolve() 传一个值,这个值会在 .then() 回调里拿到。

当你调用 new Promise() 时,JavaScript 引擎会:

  • 创建一个处于 “pending” 状态的 Promise 对象;
  • 创建两个特殊函数(通常叫 resolvereject);
  • 把这两个函数作为参数调用你的 executor 函数;
  • 当你调用 resolve() 时,触发 Promise 内部的状态变更。

需要帮忙?

用 Bricks 建站?我接客户项目。

从快速营销站到完整的 Bricks 建站,再到从 Elementor 迁移——我都做过。本站每篇教程都来自真实项目经验。告诉我你的需求,一个工作日内回复。

  • Bricks 建站与改版
  • Elementor / Divi → Bricks 迁移
  • Bricks → Astro / headless 性能升级
  • 速度优化,PageSpeed 95+ 目标