如何用jQuery/FastAPI实现并行异步调用,互不等待?
问题解决:FastAPI+jQuery聊天应用实现非阻塞后台任务
核心问题分析
当前代码的阻塞根源在后端:
/side_track接口使用了同步的time.sleep(10),会直接阻塞FastAPI的异步事件循环,导致所有后续请求(包括/submit_message)都必须等待10秒才能处理。- 前端即使不等待
side_track的响应,后端的事件循环阻塞依然会让主请求变慢。
解决方案
第一步:修复后端阻塞问题
方案A:异步化IO操作(适合可异步的耗时任务)
将同步的time.sleep替换为异步的asyncio.sleep,避免阻塞事件循环:
@app.post("/side_track") async def side_track(message_data: MessageInput): import asyncio await asyncio.sleep(10) # 异步sleep不阻塞事件循环 return {"status": "ok"}
方案B:使用BackgroundTasks(适合无法异步化的同步任务)
如果实际场景是CPU密集型或无法异步的操作(比如旧版同步数据库查询),用FastAPI的BackgroundTasks将任务放到后台执行,接口立即返回:
from fastapi import BackgroundTasks # 定义耗时的同步任务 def long_running_task(message: str): import time time.sleep(10) print(f"后台任务完成:{message}") @app.post("/side_track") async def side_track(message_data: MessageInput, background_tasks: BackgroundTasks): # 将任务添加到后台 background_tasks.add_task(long_running_task, message_data.message) # 立即返回响应,不等待任务完成 return {"status": "任务已提交至后台处理"}
第二步:前端优化(确保主流程不等待后台任务)
调整前端代码,让side_track在后台独立执行,不影响主请求的响应速度:
$(document).ready(function () { $('#message-form').submit(async function (event) { event.preventDefault(); const input_message = $('#message-form input[name=message]').val(); $('#message-list').append(`<li><strong>${input_message}</strong></li>`); // 调用后台任务,不等待结果,直接进入主请求流程 side_track(input_message); // 立即处理主请求 try { const response = await fetch('/submit_message', { method: 'POST', body: JSON.stringify({ message: input_message }), headers: { 'Content-Type': 'application/json' }, }); const data = await response.json(); $('#message-form')[0].reset(); $('#message-list').append(`<li>${data.message}</li>`); } catch (err) { console.error('主请求失败:', err); $('#message-list').append('<li><em>请求出错,请重试</em></li>'); } }); }); // 后台任务处理函数,独立执行 async function side_track(question) { try { const response = await fetch('/side_track', { method: 'POST', body: JSON.stringify({ message: question }), headers: { 'Content-Type': 'application/json' }, }); const result = await response.json(); // 可选:任务完成后通知用户 $('#message-list').append(`<li><em>后台任务状态:${result.status}</em></li>`); } catch (err) { console.error('后台任务失败:', err); } }
额外优化:修复submit_message的流式响应逻辑
如果需要保持流式返回随机数,调整后端代码使用StreamingResponse:
from fastapi.responses import StreamingResponse import asyncio import random import json async def random_numbers_stream(): while True: yield f"{json.dumps({'message': random.randint(1,10)})}\n" await asyncio.sleep(0.1) @app.post("/submit_message") async def submit_message(message_data: MessageInput): return StreamingResponse(random_numbers_stream(), media_type="application/jsonlines")
对应的前端读取逻辑也要调整为逐行读取:
// 替换主请求中的处理逻辑 const response = await fetch('/submit_message', { method: 'POST', body: JSON.stringify({ message: input_message }), headers: { 'Content-Type': 'application/json' }, }); const reader = response.body.getReader(); const decoder = new TextDecoder(); const newMessage = document.createElement('li'); $('#message-list').append(newMessage); while (true) { const { value, done } = await reader.read(); if (done) break; const data = JSON.parse(decoder.decode(value)); newMessage.innerHTML = `实时随机数:${data.message}`; }
最终效果
用户提交消息后:
- 立即显示自己的输入内容
- 主请求
/submit_message的结果(或流式数据)会实时显示 - 后台任务
/side_track在服务器端独立执行,完成后可选择性通知用户
内容的提问来源于stack exchange,提问作者Craig
相关产品推荐
相关产品推荐

