在Python中,如何实现 JavaScript 中的 Promise ?

66 阅读3分钟

这是一个非常棒的问题!JavaScript 中的 Promise 是异步编程的核心,而 Python 虽然语法不同,但也有非常相似且更强大的机制来实现同样的功能。


🎯 目标

我们要在 Python 中实现类似 JavaScript Promise 的能力:

// JavaScript Promise 示例
fetch('/api/data')
  .then(data => process(data))
  .catch(err => console.error(err))
  .finally(() => console.log('完成'))

✅ 答案:Python 中的 async/await + asyncio 就是 Promise 的“升级版”

JavaScriptPython
Promiseasyncio.Future / Task
.then()await
.catch()try/except
Promise.all()asyncio.gather()
async/awaitasync/await(语法几乎一样)

🔥 所以:Python 的 async/await 就是 Promise 的“现代、原生”实现


🧱 一、JavaScript Promise vs Python 协程(async/await)

✅ JavaScript:Promise 风格

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function main() {
  console.log("开始");
  await delay(1000);
  console.log("1秒后");
}
main();

✅ Python:async/await 风格

import asyncio

async def delay(ms):
    await asyncio.sleep(ms / 1000)  # asyncio.sleep 接受秒

async def main():
    print("开始")
    await delay(1000)
    print("1秒后")

# 运行异步函数
asyncio.run(main())

✅ 输出完全一样!


🧩 二、Python 中的 “Promise” 是什么?

Python 中没有叫 Promise 的类,但有:

1. asyncio.Future → 相当于 new Promise()

  • 表示一个“将来会完成”的结果
  • 可以手动 set_result()set_exception()
import asyncio

async def create_promise():
    future = asyncio.Future()

    # 模拟异步操作(比如 1 秒后 resolve)
    async def resolver():
        await asyncio.sleep(1)
        future.set_result("Promise 已完成!")

    # 启动解析器
    asyncio.create_task(resolver())

    # 等待结果(相当于 .then)
    result = await future
    print(result)

asyncio.run(create_promise())

输出:Promise 已完成!


🔗 三、.then().catch() 怎么实现?

Python 没有 .then(),但可以用:

✅ 方式1:await + try/except(推荐)

async def fetch_data():
    await asyncio.sleep(0.5)
    if False:  # 模拟失败
        raise Exception("网络错误")
    return {"id": 1, "name": "小明"}

async def main():
    try:
        data = await fetch_data()
        print("✅ 数据:", data)          # 相当于 .then()
    except Exception as e:
        print("❌ 错误:", e)             # 相当于 .catch()
    finally:
        print("🎉 完成")                # 相当于 .finally()

asyncio.run(main())

🔄 四、Promise.all() 怎么实现?

JavaScript:

Promise.all([p1, p2, p3]).then(results => ...)

Python:

import asyncio

async def task1(): await asyncio.sleep(1); return "结果1"
async def task2(): await asyncio.sleep(2); return "结果2"
async def task3(): await asyncio.sleep(1); return "结果3"

async def main():
    # 相当于 Promise.all()
    results = await asyncio.gather(
        task1(),
        task2(),
        task3()
    )
    print(results)  # ['结果1', '结果2', '结果3']

asyncio.run(main())

✅ 并发执行,等待所有完成


⏳ 五、Promise.race() 怎么实现?

JavaScript:哪个 Promise 先完成就用哪个

Python:

async def slow(): await asyncio.sleep(2); return "慢"
async def fast(): await asyncio.sleep(1); return "快"

async def main():
    result = await asyncio.wait(
        [slow(), fast()],
        return_when=asyncio.FIRST_COMPLETED
    )
    done, pending = result
    print("最先完成:", done.pop().result())  # 快

asyncio.run(main())

📦 六、封装一个类 Promise 的工具(可选)

如果你真的想要 .then().catch() 风格,可以封装:

class Promise:
    def __init__(self, coro):
        self.task = asyncio.create_task(coro)
    
    def then(self, success):
        async def wrapper():
            try:
                result = await self.task
                return success(result)
            except Exception as e:
                return self._error or (lambda err: None)(e)
        return Promise(wrapper())
    
    def catch(self, failure):
        self._error = failure
        return self

# 使用示例
async def get_data():
    await asyncio.sleep(1)
    return "Hello"

def on_success(data):
    print("成功:", data)

def on_error(err):
    print("失败:", err)

# Promise 风格调用
Promise(get_data()).then(on_success).catch(on_error)

# 但需要运行事件循环
asyncio.run(asyncio.sleep(2))  # 等待完成

💡 但这不是 Python 风格,推荐直接用 async/await


✅ 七、Python vs JavaScript 异步对比总结

功能JavaScriptPython
定义异步函数async function fn()async def fn():
等待异步结果await promiseawait coro
错误处理.catch()try/catchtry/except
并发多个任务Promise.all()asyncio.gather()
竞速Promise.race()asyncio.wait(..., FIRST_COMPLETED)
创建“Promise”new Promise()asyncio.Future()
运行事件循环浏览器自动asyncio.run()

🎯 八、最佳实践:Python 中如何“正确”使用 Promise 思维

  1. ✅ 使用 async/await 写异步代码
  2. ✅ 用 asyncio.gather() 并发请求
  3. ✅ 用 try/except 处理错误
  4. ✅ 不要手动封装 .then(),那是 JS 的风格
  5. ✅ 所有异步入口用 asyncio.run()

🚀 九、实战示例:并发获取多个 API 数据

import asyncio
import aiohttp  # 需要安装: pip install aiohttp

async def fetch(session, url):
    async with session.get(url) as res:
        return await res.json()

async def main():
    urls = [
        'https://jsonplaceholder.typicode.com/posts/1',
        'https://jsonplaceholder.typicode.com/posts/2',
        'https://jsonplaceholder.typicode.com/posts/3',
    ]

    async with aiohttp.ClientSession() as session:
        try:
            results = await asyncio.gather(
                *[fetch(session, url) for url in urls],
                return_exceptions=True  # 某个失败不影响其他
            )
            for i, r in enumerate(results):
                if isinstance(r, Exception):
                    print(f"请求 {i+1} 失败: {r}")
                else:
                    print(f"请求 {i+1} 成功: {r['title']}")
        except Exception as e:
            print("批量请求失败:", e)

asyncio.run(main())

✅ 这就是 Python 中的“Promise.all()”最佳实践!


✅ 总结

Python 有 Promise 吗?没有叫 Promise 的类,但有更强大的 async/await
怎么实现 .then().catch()await + try/except
Promise.all() 对应什么?asyncio.gather()
推荐写法?直接用 async/await,不要模仿 JS 风格

🎯 记住:Python 的 async/await 不是模仿 Promise,而是它的“进化版”