无锡市本地信息网

JavaScript通过外卖订单讲解异步编程

2026-05-01 07:06:02 浏览次数:0
详细信息

JavaScript异步编程:外卖订单实战讲解

让我们通过一个生动的外卖订单例子来理解JavaScript异步编程的核心概念。

1. 同步 vs 异步:直观对比

同步(排队点餐)

// 同步方式 - 一个人点完下一个人才能点
function synchronousOrder() {
    console.log("1. 顾客A开始点餐");
    // 模拟点餐耗时
    for(let i = 0; i < 1000000000; i++) {} // 阻塞操作
    console.log("2. 顾客A点餐完成");

    console.log("3. 顾客B开始点餐");
    for(let i = 0; i < 1000000000; i++) {} // 再次阻塞
    console.log("4. 顾客B点餐完成");

    console.log("5. 顾客C开始点餐");
    for(let i = 0; i < 1000000000; i++) {} // 再次阻塞
    console.log("6. 顾客C点餐完成");
}

synchronousOrder();
// 结果:必须按顺序完成,顾客B和C只能等待

异步(外卖平台接单)

// 异步方式 - 平台可以同时处理多个订单
console.log("1. 平台:开始接受新订单");

setTimeout(() => {
    console.log("2. 订单A:商家已接单");
}, 1000);

console.log("3. 平台:继续接受其他订单");

setTimeout(() => {
    console.log("4. 订单B:商家已接单");
}, 800);

console.log("5. 平台:订单处理中...");

// 结果:订单不会互相阻塞,可以并行处理

2. 完整外卖订单流程示例

// 模拟一个完整的外卖订单流程
class FoodDelivery {
    constructor(orderId, customerName, items) {
        this.orderId = orderId;
        this.customerName = customerName;
        this.items = items;
        this.status = "pending";
    }

    // 模拟异步操作:提交订单
    placeOrder() {
        return new Promise((resolve, reject) => {
            console.log(`🛒 [${this.orderId}] ${this.customerName}提交订单: ${this.items.join(', ')}`);

            setTimeout(() => {
                const success = Math.random() > 0.1; // 90%成功率
                if (success) {
                    this.status = "order_placed";
                    console.log(`✅ [${this.orderId}] 订单提交成功`);
                    resolve(this);
                } else {
                    console.log(`❌ [${this.orderId}] 订单提交失败`);
                    reject("支付失败");
                }
            }, 1000);
        });
    }

    // 模拟异步操作:商家准备
    prepareFood() {
        return new Promise((resolve) => {
            console.log(`👨‍🍳 [${this.orderId}] 商家开始制作...`);

            // 模拟制作时间(不同菜品时间不同)
            const prepTime = this.items.length * 500 + Math.random() * 1000;

            setTimeout(() => {
                this.status = "food_ready";
                console.log(`🍱 [${this.orderId}] 菜品制作完成 (耗时: ${prepTime.toFixed(0)}ms)`);
                resolve(this);
            }, prepTime);
        });
    }

    // 模拟异步操作:骑手取餐
    pickupOrder() {
        return new Promise((resolve) => {
            console.log(`🛵 [${this.orderId}] 骑手前往商家...`);

            setTimeout(() => {
                this.status = "picked_up";
                console.log(`📦 [${this.orderId}] 骑手已取餐`);
                resolve(this);
            }, 1500);
        });
    }

    // 模拟异步操作:配送
    deliverOrder() {
        return new Promise((resolve) => {
            console.log(`🚚 [${this.orderId}] 骑手配送中...`);

            // 模拟配送时间(受交通影响)
            const deliveryTime = 2000 + Math.random() * 2000;

            setTimeout(() => {
                this.status = "delivered";
                console.log(`🎉 [${this.orderId}] 订单已送达!`);
                resolve(this);
            }, deliveryTime);
        });
    }
}

// 使用Promise处理单个订单
function processSingleOrder(order) {
    console.log("\n======= 处理单个订单 =======");

    order.placeOrder()
        .then(order => order.prepareFood())
        .then(order => order.pickupOrder())
        .then(order => order.deliverOrder())
        .then(order => {
            console.log(`💝 [${order.orderId}] 订单完成,状态: ${order.status}`);
        })
        .catch(error => {
            console.log(`⚠️  订单出错: ${error}`);
        });
}

// 使用async/await处理订单(更优雅的方式)
async function processOrderAsync(order) {
    try {
        console.log("\n======= 使用async/await处理订单 =======");

        await order.placeOrder();
        await order.prepareFood();
        await order.pickupOrder();
        await order.deliverOrder();

        console.log(`💝 [${order.orderId}] 订单完成,状态: ${order.status}`);
        return order;
    } catch (error) {
        console.log(`⚠️  订单出错: ${error}`);
        throw error;
    }
}

// 处理多个并发订单
async function processMultipleOrders() {
    console.log("\n======= 处理多个并发订单 =======");

    // 创建多个订单
    const orders = [
        new FoodDelivery("ORDER001", "张三", ["红烧肉", "米饭", "可乐"]),
        new FoodDelivery("ORDER002", "李四", ["披萨", "沙拉"]),
        new FoodDelivery("ORDER003", "王五", ["汉堡", "薯条", "冰淇淋"])
    ];

    // 同时开始所有订单(并行)
    const orderPromises = orders.map(order => 
        order.placeOrder()
            .then(order => order.prepareFood())
            .then(order => order.pickupOrder())
            .then(order => order.deliverOrder())
            .catch(error => {
                console.log(`订单${order.orderId}失败: ${error}`);
                return null;
            })
    );

    // 等待所有订单完成
    const results = await Promise.allSettled(orderPromises);

    console.log("\n======= 所有订单处理完成 =======");
    const successfulOrders = results.filter(result => result.status === 'fulfilled' && result.value);
    console.log(`成功送达: ${successfulOrders.length} 个订单`);
}

// 执行示例
const testOrder = new FoodDelivery("TEST001", "测试用户", ["宫保鸡丁", "蛋炒饭"]);

// 方法1: 使用Promise链式调用
processSingleOrder(testOrder);

// 方法2: 使用async/await(需要稍后执行避免时间重叠)
setTimeout(async () => {
    const order2 = new FoodDelivery("TEST002", "async用户", ["牛肉面", "小菜"]);
    await processOrderAsync(order2);

    // 方法3: 处理多个并发订单
    await processMultipleOrders();
}, 5000);

3. 关键异步模式对比

// 1. 回调地狱(Callback Hell) - 不推荐
function callbackHellExample() {
    placeOrder((order) => {
        prepareFood(order, (food) => {
            pickupOrder(food, (delivery) => {
                deliverOrder(delivery, (result) => {
                    console.log("送达!");
                    // 如果还有更多步骤...代码会向右无限延伸
                });
            });
        });
    });
}

// 2. Promise链式调用 - 改进版
function promiseChainExample() {
    placeOrder()
        .then(order => prepareFood(order))
        .then(food => pickupOrder(food))
        .then(delivery => deliverOrder(delivery))
        .then(result => console.log("送达!"))
        .catch(error => console.error("出错:", error));
}

// 3. async/await - 现代推荐
async function asyncAwaitExample() {
    try {
        const order = await placeOrder();
        const food = await prepareFood(order);
        const delivery = await pickupOrder(food);
        const result = await deliverOrder(delivery);
        console.log("送达!");
    } catch (error) {
        console.error("出错:", error);
    }
}

// 4. 并行处理多个异步操作
async function parallelProcessing() {
    // 同时开始多个独立操作
    const [userInfo, restaurantInfo, promoInfo] = await Promise.all([
        getUserInfo(),
        getRestaurantInfo(),
        getPromotionInfo()
    ]);

    console.log("所有信息已获取,可以下单");
}

// 5. 竞速模式:哪个先完成用哪个
async function raceExample() {
    // 从多个骑手中选择最先接单的
    const fastestRider = await Promise.race([
        findRider("平台A"),
        findRider("平台B"),
        findRider("平台C")
    ]);

    console.log(`最快的骑手: ${fastestRider.name}`);
}

4. 实际应用示例:订单状态跟踪

// 外卖订单状态实时跟踪系统
class OrderTracker {
    constructor() {
        this.orders = new Map();
        this.statusCallbacks = new Map();
    }

    // 创建订单并跟踪
    async createAndTrackOrder(customer, items) {
        const orderId = `ORDER_${Date.now()}`;
        const order = new FoodDelivery(orderId, customer, items);

        this.orders.set(orderId, order);

        // 开始跟踪订单状态
        this.trackOrder(orderId);

        return orderId;
    }

    // 跟踪订单状态变化
    async trackOrder(orderId) {
        const order = this.orders.get(orderId);

        if (!order) return;

        const statusCheck = setInterval(async () => {
            const previousStatus = order.status;

            // 模拟状态更新(实际中可能来自WebSocket或API轮询)
            const statuses = ["order_placed", "food_ready", "picked_up", "delivered"];
            const currentIndex = statuses.indexOf(previousStatus);

            if (currentIndex < statuses.length - 1) {
                // 模拟状态前进
                if (Math.random() > 0.7) {
                    order.status = statuses[currentIndex + 1];
                    console.log(`📱 [${orderId}] 状态更新: ${previousStatus} → ${order.status}`);

                    // 触发回调
                    this.triggerCallbacks(orderId, order.status);

                    // 如果送达,停止跟踪
                    if (order.status === "delivered") {
                        clearInterval(statusCheck);
                        console.log(`📱 [${orderId}] 跟踪结束`);
                    }
                }
            }
        }, 2000);
    }

    // 注册状态变化回调
    onStatusChange(orderId, callback) {
        if (!this.statusCallbacks.has(orderId)) {
            this.statusCallbacks.set(orderId, []);
        }
        this.statusCallbacks.get(orderId).push(callback);
    }

    // 触发所有回调
    triggerCallbacks(orderId, status) {
        const callbacks = this.statusCallbacks.get(orderId) || [];
        callbacks.forEach(callback => {
            try {
                callback(status);
            } catch (error) {
                console.error("回调执行错误:", error);
            }
        });
    }
}

// 使用示例
async function demoOrderTracking() {
    console.log("\n======= 订单实时跟踪演示 =======");

    const tracker = new OrderTracker();

    // 创建订单
    const orderId = await tracker.createAndTrackOrder("跟踪用户", ["麻辣香锅", "米饭"]);

    // 注册状态变化监听
    tracker.onStatusChange(orderId, (status) => {
        const statusMessages = {
            "order_placed": "商家已接单",
            "food_ready": "菜品已制作完成",
            "picked_up": "骑手已取餐",
            "delivered": "已送达"
        };

        console.log(`📲 通知: 订单${orderId} ${statusMessages[status] || status}`);

        // 可以在这里更新UI、发送通知等
        if (status === "delivered") {
            console.log("🎊 订单完成!请给骑手评价");
        }
    });

    console.log(`开始跟踪订单: ${orderId}`);
    console.log("等待状态更新...\n");
}

// 运行演示
demoOrderTracking();

5. 关键概念总结

概念 外卖订单比喻 JavaScript实现
同步 一个订单完全处理完才处理下一个 阻塞操作,代码顺序执行
异步 同时处理多个订单,不互相等待 非阻塞,使用回调/Promise/async-await
回调函数 订单状态更新时打电话通知你 function callback(error, result) {}
Promise 订单承诺:一定会送达或通知失败 new Promise((resolve, reject) => {})
async/await "等待"订单完成再继续下一步 async function() { await task(); }
并行处理 多个餐厅同时准备不同菜品 Promise.all([task1, task2, task3])
竞速模式 多个骑手抢单,第一个接单的配送 Promise.race([rider1, rider2])

6. 练习建议

修改示例代码,添加订单取消功能 实现一个超时机制:如果30分钟未送达自动取消 创建订单队列系统,控制同时处理的订单数量 添加重试机制:骑手取消后自动重新分配

通过这个外卖订单的例子,你可以直观地理解JavaScript异步编程的核心概念。异步编程的本质就是"不等待",让程序在等待一个操作完成时,可以继续处理其他任务,就像外卖平台可以同时处理无数订单一样。

相关推荐