You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中无需刷新实时返回函数数据至客户端的解决方案

问题分析

你的核心问题是同步阻塞函数match_algo()卡住了异步WebSocket的事件循环,导致连接超时断开。AsyncWebsocketConsumer基于异步IO模型运行,一旦调用同步耗时函数,整个事件循环会被阻塞,WebSocket服务器无法响应心跳或其他请求,最终被判定为超时断开。

修复方案一:适配异步WebSocket的同步耗时函数

把同步的match_algo()放到线程池执行,避免阻塞异步事件循环:

修改consumer.py

import asyncio
from asgiref.sync import sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer
import json

class LoadingConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()

        # 发送加载中消息
        await self.send(text_data=json.dumps({
            'message': 'loading...',
            "status": False
        }))

        # 用sync_to_async将同步函数转为异步,通过线程池执行
        data = await sync_to_async(match_algo)()

        # 发送结果消息(取消注释传递真实数据)
        await self.send(text_data=json.dumps({
            'message': "loaded",
            "status": True,
            "matches": data
        }))

        await self.close()

关键说明:

  • sync_to_async是Django内置工具,自动将同步函数包装为异步执行,默认使用线程池,不会阻塞异步事件循环。
  • 若match_algo()涉及数据库操作,Django ORM默认线程安全,无需额外处理。

前端动态渲染数据

把前端固定表格替换为基于data.matches的动态渲染:

socket.onmessage = function(event) {
    const data = JSON.parse(event.data);
    
    if (data.status) {
        // 动态生成表格行
        const rows = data.matches.map(item => `
            <tr>
                <td>${item.name}</td>
                <td>${item.specialty}</td>
                <td>${item.experience}</td>
                <td>${item.contact}</td>
            </tr>
        `).join('');
        
        const tableHTML = `
        <table>
          <thead>
            <tr>
              <th>Name</th>
              <th>Specialty</th>
              <th>Experience</th>
              <th>Contact</th>
            </tr>
          </thead>
          <tbody>${rows}</tbody>
        </table>
        `;

        document.getElementById('therapist-table-container').innerHTML = tableHTML;
      } else {
        document.getElementById('therapist-table-container').innerHTML = 'Matching Therapist suitable for you. Please wait.';
      }
};
修复方案二:Celery + AJAX(适合超长耗时任务)

如果match_algo()运行时间超过10秒,用Celery异步任务+前端轮询会更稳定,避免WebSocket超时问题:

步骤1:定义Celery异步任务

# tasks.py
from celery import shared_task

@shared_task
def run_match_algo():
    return match_algo()

步骤2:编写视图函数

# views.py
from django.http import JsonResponse
from django.shortcuts import render
from .tasks import run_match_algo
from celery.result import AsyncResult

def redirected_page(request):
    return render(request, 'redirected_page.html')

def trigger_match(request):
    # 触发异步任务
    task = run_match_algo.delay()
    return JsonResponse({'task_id': task.id})

def check_task_status(request, task_id):
    task = AsyncResult(task_id)
    if task.ready():
        return JsonResponse({'status': 'success', 'data': task.result})
    else:
        return JsonResponse({'status': 'pending'})

步骤3:前端轮询实现

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Therapist Details</title>
    <style>
        table { width: 100%; border-collapse: collapse; }
        th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
        th { background-color: #f2f2f2; }
        body { margin : 80px 150px }
    </style>
</head>
<body>
    <h1>Therapist Details</h1>
    <div id="therapist-table-container">
        Matching Therapist suitable for you. Please wait.
    </div>

    <script>
        window.onload = function() {
            // 触发异步任务
            fetch('/trigger-match/')
                .then(res => res.json())
                .then(data => {
                    // 每秒轮询任务状态
                    const pollInterval = setInterval(() => {
                        fetch(`/check-task-status/${data.task_id}/`)
                            .then(res => res.json())
                            .then(taskData => {
                                if (taskData.status === 'success') {
                                    clearInterval(pollInterval);
                                    // 渲染结果表格
                                    const rows = taskData.data.map(item => `
                                        <tr>
                                            <td>${item.name}</td>
                                            <td>${item.specialty}</td>
                                            <td>${item.experience}</td>
                                            <td>${item.contact}</td>
                                        </tr>
                                    `).join('');
                                    const tableHTML = `
                                    <table>
                                      <thead>
                                        <tr>
                                          <th>Name</th>
                                          <th>Specialty</th>
                                          <th>Experience</th>
                                          <th>Contact</th>
                                        </tr>
                                      </thead>
                                      <tbody>${rows}</tbody>
                                    </table>
                                    `;
                                    document.getElementById('therapist-table-container').innerHTML = tableHTML;
                                }
                            });
                    }, 1000);
                });
        };
    </script>
</body>
</html>

方案对比

  • WebSocket方案:适合实时性要求高、耗时中等的任务,无需频繁轮询。
  • Celery+AJAX方案:适合超长耗时任务,稳定性更强,支持任务重试、状态记录。
额外注意事项
  • 确保match_algo()返回的数据可被JSON序列化,若返回模型对象,需先转为字典(比如用model_to_dict)。
  • 使用WebSocket时,需配置Daphne等ASGI服务器,保证异步环境正常运行。

内容的提问来源于stack exchange,提问作者Hamdan Salih

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 00:49:57