{"id":90032,"date":"2026-08-04T16:17:43","date_gmt":"2026-08-04T08:17:43","guid":{"rendered":"https:\/\/www.wsisp.com\/helps\/90032.html"},"modified":"2026-08-04T16:17:43","modified_gmt":"2026-08-04T08:17:43","slug":"fastapi-sse-websocket-%e5%a5%b6%e8%8c%b6%e5%ba%97%e5%ae%9e%e6%97%b6%e8%ae%a2%e5%8d%95%e7%9c%8b%e6%9d%bf","status":"publish","type":"post","link":"https:\/\/www.wsisp.com\/helps\/90032.html","title":{"rendered":"fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f"},"content":{"rendered":"<h2>fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f<\/h2>\n<p>\u7528 FastAPI \u4ece\u96f6\u642d\u4e00\u4e2a\u300c\u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f\u300d&#xff0c;\u628a SSE&#xff08;\u5355\u5411\u63a8\u9001&#xff09; \u548c WebSocket&#xff08;\u53cc\u5411\u901a\u9053&#xff09; \u4e24\u4e2a\u5b9e\u65f6\u901a\u4fe1\u6280\u672f\u653e\u5728\u540c\u4e00\u4e2a\u9879\u76ee\u91cc\u5bf9\u6bd4\u5b66\u4e60\u3002<\/p>\n<p>\u8fd9\u4efd\u6559\u53ea\u8981\u8ddf\u7740\u7ae0\u8282\u987a\u5e8f\u8bfb\u3001\u6309\u6b65\u9aa4\u6572\u4ee3\u7801&#xff0c;\u5c31\u80fd\u72ec\u7acb\u5199\u5b8c\u6240\u6709\u6587\u4ef6\u5e76\u8ba9\u9879\u76ee\u8dd1\u8d77\u6765\u3002\u6bcf\u4e00\u7ae0\u90fd\u5305\u542b&#xff1a;<\/p>\n<li>\u672c\u7ae0\u76ee\u6807 \u2014\u2014 \u8fd9\u7ae0\u8981\u89e3\u51b3\u4ec0\u4e48\u95ee\u9898&#xff1b;<\/li>\n<li>\u539f\u59cb\u5b8c\u6574\u4ee3\u7801 \u2014\u2014 \u76f4\u63a5\u7167\u6284\u5373\u53ef&#xff0c;\u4e0d\u7701\u7565\u4efb\u4f55\u4e00\u884c&#xff1b;<\/li>\n<li>\u9010\u884c\u8bb2\u89e3 \u2014\u2014 \u5173\u952e\u4ee3\u7801\u4e3a\u4ec0\u4e48\u8fd9\u6837\u5199&#xff1b;<\/li>\n<li>\u52a8\u624b\u9a8c\u8bc1 \u2014\u2014 \u8fd9\u4e00\u6b65\u505a\u5b8c\u5e94\u8be5\u770b\u5230\u4ec0\u4e48\u3002<\/li>\n<hr \/>\n<h3>&#x1f4d6; \u672c\u5408\u8ba2\u672c\u76ee\u5f55<\/h3>\n<table>\n<tr>\u7ae0\u6807\u9898\u8df3\u8f6c<\/tr>\n<tbody>\n<tr>\n<td>0<\/td>\n<td>\u9879\u76ee\u6982\u8ff0<\/td>\n<td>\u2192 \u7b2c 0 \u7ae0<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>\u73af\u5883\u4e0e\u9879\u76ee\u9aa8\u67b6<\/td>\n<td>\u2192 \u7b2c 1 \u7ae0<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>\u6570\u636e\u5c42 models.py<\/td>\n<td>\u2192 \u7b2c 2 \u7ae0<\/td>\n<\/tr>\n<tr>\n<td>3<\/td>\n<td>SSE \u6a21\u5757 sse.py<\/td>\n<td>\u2192 \u7b2c 3 \u7ae0<\/td>\n<\/tr>\n<tr>\n<td>4<\/td>\n<td>WebSocket \u6a21\u5757 ws.py<\/td>\n<td>\u2192 \u7b2c 4 \u7ae0<\/td>\n<\/tr>\n<tr>\n<td>5<\/td>\n<td>\u5e7f\u64ad\u5668 broadcaster.py<\/td>\n<td>\u2192 \u7b2c 5 \u7ae0<\/td>\n<\/tr>\n<tr>\n<td>6<\/td>\n<td>\u5e94\u7528\u5165\u53e3 app.py<\/td>\n<td>\u2192 \u7b2c 6 \u7ae0<\/td>\n<\/tr>\n<tr>\n<td>7<\/td>\n<td>\u524d\u7aef\u770b\u677f index.html<\/td>\n<td>\u2192 \u7b2c 7 \u7ae0<\/td>\n<\/tr>\n<tr>\n<td>8<\/td>\n<td>\u8fd0\u884c\u4e0e\u9a8c\u8bc1<\/td>\n<td>\u2192 \u7b2c 8 \u7ae0<\/td>\n<\/tr>\n<tr>\n<td>9<\/td>\n<td>SSE vs WebSocket \u5bf9\u6bd4\u4e0e\u6269\u5c55\u7ec3\u4e60<\/td>\n<td>\u2192 \u7b2c 9 \u7ae0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>&#x1f3af; \u5b66\u5b8c\u4f60\u80fd\u505a\u5230\u4ec0\u4e48<\/h3>\n<ul>\n<li>\u7406\u89e3 HTTP \u957f\u8fde\u63a5 \u7684\u4e24\u79cd\u5b9e\u73b0\u65b9\u5f0f&#xff08;SSE \/ WebSocket&#xff09;\u53ca\u5176\u5dee\u5f02&#xff1b;<\/li>\n<li>\u7528 FastAPI \u5199\u51fa\u4e00\u4e2a\u540e\u53f0\u5e7f\u64ad\u4efb\u52a1&#xff08;\u5fc3\u8df3\u6e90&#xff09;&#xff0c;\u6bcf 0.8 \u79d2\u63a8\u8fdb\u4e00\u6b21\u8ba2\u5355\u72b6\u6001&#xff1b;<\/li>\n<li>\u7528 StreamingResponse \u5b9e\u73b0 SSE&#xff0c;\u8ba9\u6d4f\u89c8\u5668\u300c\u53ea\u8bfb\u300d\u5730\u63a5\u6536\u5b9e\u65f6\u8ba2\u5355&#xff1b;<\/li>\n<li>\u7528 WebSocket \u5b9e\u73b0\u53cc\u5411\u901a\u9053&#xff0c;\u8ba9\u524d\u7aef\u53d1\u547d\u4ee4&#xff08;ping \/ \u52a0\u5355 \/ \u53d6\u9910 \/ \u5feb\u7167&#xff09;\u5e76\u62ff\u5230\u56de\u6267&#xff1b;<\/li>\n<li>\u5199\u4e00\u4e2a\u7eaf\u524d\u7aef\u9875\u9762&#xff08;EventSource &#043; WebSocket&#xff09;&#xff0c;\u628a\u5b9e\u65f6\u6570\u636e\u6e32\u67d3\u6210\u5361\u7247\u770b\u677f&#xff1b;<\/li>\n<li>\u72ec\u7acb\u5b8c\u6210\u9879\u76ee\u9aa8\u67b6 \u2192 \u6570\u636e\u5c42 \u2192 \u4f20\u8f93\u5c42 \u2192 \u5165\u53e3 \u2192 \u524d\u7aef \u2192 \u8fd0\u884c\u5168\u6d41\u7a0b\u3002<\/li>\n<\/ul>\n<h3>&#x1f6e0; \u6280\u672f\u6808<\/h3>\n<table>\n<tr>\u5c42\u6280\u672f<\/tr>\n<tbody>\n<tr>\n<td>\u540e\u7aef\u6846\u67b6<\/td>\n<td>FastAPI 0.141&#043;<\/td>\n<\/tr>\n<tr>\n<td>ASGI \u670d\u52a1\u5668<\/td>\n<td>Uvicorn 0.52&#043;<\/td>\n<\/tr>\n<tr>\n<td>\u4f20\u8f93\u534f\u8bae<\/td>\n<td>SSE&#xff08;text\/event-stream&#xff09;&#043; WebSocket<\/td>\n<\/tr>\n<tr>\n<td>\u5305\u7ba1\u7406<\/td>\n<td>uv&#xff08;\u63a8\u8350&#xff09;\/ pip<\/td>\n<\/tr>\n<tr>\n<td>Python \u7248\u672c<\/td>\n<td>3.14<\/td>\n<\/tr>\n<tr>\n<td>\u524d\u7aef<\/td>\n<td>\u539f\u751f HTML &#043; CSS &#043; JS&#xff08;\u65e0\u6846\u67b6&#xff09;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>&#x1f4c1; \u6700\u7ec8\u76ee\u5f55\u7ed3\u6784<\/h3>\n<p>fastapi-sse-ws-\u5976\u8336\u770b\u677f\/<br \/>\n\u251c\u2500\u2500 pyproject.toml          # \u4f9d\u8d56\u4e0e\u9879\u76ee\u5143\u4fe1\u606f<br \/>\n\u251c\u2500\u2500 .python-version         # \u56fa\u5b9a Python \u7248\u672c &#061; 3.14<br \/>\n\u251c\u2500\u2500 .gitignore<br \/>\n\u251c\u2500\u2500 docs\/                   # \u6559\u7a0b\u76ee\u5f55&#xff08;\u5206\u7ae0\u539f\u6587\u4ef6 &#043; \u672c\u5408\u8ba2\u672c&#xff09;<br \/>\n\u2502   \u251c\u2500\u2500 README.md<br \/>\n\u2502   \u251c\u2500\u2500 00-\u9879\u76ee\u6982\u8ff0.md ~ 09-SSE-vs-WebSocket.md<br \/>\n\u2502   \u251c\u2500\u2500 \u6559\u7a0b\u5408\u8ba2\u672c.md        # \u2190 \u672c\u6587\u4ef6<br \/>\n\u2502   \u251c\u2500\u2500 dashboard.png       # \u8fd0\u884c\u622a\u56fe&#xff08;SSE \u770b\u677f&#xff09;<br \/>\n\u2502   \u2514\u2500\u2500 dashboard-ws.png    # \u8fd0\u884c\u622a\u56fe&#xff08;WS \u64cd\u4f5c\u53f0 &#043; \u901a\u4fe1\u65e5\u5fd7&#xff09;<br \/>\n\u251c\u2500\u2500 src\/                    # \u540e\u7aef Python \u5305<br \/>\n\u2502   \u251c\u2500\u2500 __init__.py<br \/>\n\u2502   \u251c\u2500\u2500 app.py              # FastAPI \u5e94\u7528\u5165\u53e3<br \/>\n\u2502   \u251c\u2500\u2500 broadcaster.py       # \u540e\u53f0\u5e7f\u64ad\u4efb\u52a1&#xff08;\u5fc3\u8df3\u6e90&#xff09;<br \/>\n\u2502   \u251c\u2500\u2500 models.py           # \u6570\u636e\u5c42&#xff1a;\u83dc\u5355 \/ \u8ba2\u5355 \/ \u63a8\u8fdb\u903b\u8f91<br \/>\n\u2502   \u251c\u2500\u2500 sse.py              # SSE \u8def\u7531<br \/>\n\u2502   \u2514\u2500\u2500 ws.py               # WebSocket \u8def\u7531<br \/>\n\u2514\u2500\u2500 static\/<br \/>\n    \u2514\u2500\u2500 index.html          # \u524d\u7aef\u770b\u677f\u9875\u9762<\/p>\n<h3>&#x1f680; 30 \u79d2\u901f\u89c8<\/h3>\n<p><span class=\"token comment\"># 1. \u5b89\u88c5\u4f9d\u8d56&#xff08;\u7528 uv&#xff0c;\u66f4\u5feb&#xff1b;\u6ca1\u6709 uv \u7528 pip \u4e5f\u884c&#xff0c;\u89c1\u7b2c 1 \u7ae0&#xff09;<\/span><br \/>\nuv <span class=\"token function\">sync<\/span>                       <span class=\"token comment\"># \u6216: pip install fastapi &#034;uvicorn[standard]&#034; websockets<\/span><\/p>\n<p><span class=\"token comment\"># 2. \u542f\u52a8\u670d\u52a1<\/span><br \/>\nuv run python <span class=\"token parameter variable\">-m<\/span> uvicorn src.app:app <span class=\"token parameter variable\">&#8211;host<\/span> <span class=\"token number\">127.0<\/span>.0.1 <span class=\"token parameter variable\">&#8211;port<\/span> <span class=\"token number\">8000<\/span> <span class=\"token parameter variable\">&#8211;reload<\/span><\/p>\n<p><span class=\"token comment\"># 3. \u6253\u5f00\u6d4f\u89c8\u5668<\/span><br \/>\n<span class=\"token comment\">#    http:\/\/127.0.0.1:8000\/<\/span><\/p>\n<p>\u542f\u52a8\u6210\u529f\u540e\u4f60\u4f1a\u770b\u5230\u8fd9\u6837\u7684\u770b\u677f&#xff08;\u5de6 SSE \u5355\u5411\u63a8\u9001\u3001\u53f3 WebSocket \u53cc\u5411\u901a\u9053&#xff09;&#xff1a;<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/08\/20260804081737-6a71a021780c1.png\" alt=\"\u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f\u8fd0\u884c\u622a\u56fe\" \/><\/p>\n<p>\u70b9\u4e00\u4e0b\u53f3\u4e0b\u89d2\u7684\u64cd\u4f5c\u53f0\u6309\u94ae&#xff0c;\u8fd8\u80fd\u770b\u5230 WebSocket \u7684\u53cc\u5411\u901a\u4fe1\u65e5\u5fd7&#xff1a;<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/08\/20260804081737-6a71a021e51d4.png\" alt=\"WebSocket \u64cd\u4f5c\u53f0\u4e0e\u901a\u4fe1\u65e5\u5fd7\" \/><\/p>\n<hr \/>\n<hr \/>\n<h2>\u7b2c 0 \u7ae0 \u00b7 \u9879\u76ee\u6982\u8ff0<\/h2>\n<h3>\u672c\u7ae0\u76ee\u6807<\/h3>\n<p>\u5728\u770b\u4efb\u4f55\u4ee3\u7801\u4e4b\u524d&#xff0c;\u5148\u7528\u4e00\u5f20\u56fe\u3001\u4e00\u5f20\u622a\u56fe\u641e\u6e05\u695a\u4e09\u4ef6\u4e8b&#xff1a;<\/p>\n<li>\u8fd9\u4e2a\u9879\u76ee\u505a\u4e86\u4ec0\u4e48&#xff1b;<\/li>\n<li>SSE \u548c WebSocket \u5404\u81ea\u7684\u804c\u8d23&#xff1b;<\/li>\n<li>\u6570\u636e\u662f\u600e\u4e48\u6d41\u52a8\u7684\u3002<\/li>\n<p>\u5efa\u7acb\u5168\u5c40\u89c2\u4e4b\u540e&#xff0c;\u540e\u9762\u6bcf\u4e00\u7ae0\u7684\u4ee3\u7801\u4f60\u5c31\u77e5\u9053\u5b83\u300c\u5b89\u5728\u54ea\u4e00\u5c42\u300d\u3002<\/p>\n<hr \/>\n<h3>0.1 \u9879\u76ee\u505a\u4e86\u4ec0\u4e48<\/h3>\n<p>\u6a21\u62df\u4e00\u5bb6\u5976\u8336\u5e97\u7684\u5b9e\u65f6\u8ba2\u5355\u770b\u677f&#xff1a;<\/p>\n<ul>\n<li>\u540e\u53f0\u6bcf 0.8 \u79d2 \u81ea\u52a8\u63a8\u8fdb\u4e00\u6b21\u6240\u6709\u8ba2\u5355\u7684\u5236\u4f5c\u8fdb\u5ea6&#xff08;\u5f85\u5236\u4f5c \u2192 \u5236\u4f5c\u4e2d \u2192 \u5df2\u5b8c\u6210 \u2192 \u5df2\u53d6\u9910&#xff09;&#xff0c;\u5076\u5c14\u968f\u673a\u751f\u6210\u65b0\u8ba2\u5355&#xff1b;<\/li>\n<li>\u5de6\u4fa7\u770b\u677f\u7528 SSE&#xff08;\u5355\u5411\u63a8\u9001&#xff09;&#xff1a;\u670d\u52a1\u5668\u53ea\u7ba1\u5f80\u4e0b\u63a8\u6700\u65b0\u8ba2\u5355\u5217\u8868&#xff0c;\u6d4f\u89c8\u5668\u53ea\u7ba1\u6536\u548c\u6e32\u67d3&#xff1b;<\/li>\n<li>\u53f3\u4fa7\u64cd\u4f5c\u53f0\u7528 WebSocket&#xff08;\u53cc\u5411\u901a\u9053&#xff09;&#xff1a;\u5e97\u5458\u53ef\u4ee5\u4e3b\u52a8\u53d1\u547d\u4ee4\u2014\u2014ping&#xff08;\u63a2\u6d3b&#xff09;\u3001add&#xff08;\u52a0\u5355&#xff09;\u3001pickup&#xff08;\u53d6\u9910&#xff09;\u3001snapshot&#xff08;\u62c9\u5feb\u7167&#xff09;\u2014\u2014\u670d\u52a1\u5668\u5bf9\u6bcf\u6761\u547d\u4ee4\u7ed9\u660e\u786e\u56de\u6267\u3002<\/li>\n<\/ul>\n<p>\u8bbe\u8ba1\u610f\u56fe&#xff1a;\u628a\u4e24\u79cd\u5b9e\u65f6\u6280\u672f\u653e\u5728\u540c\u4e00\u4e2a\u6570\u636e\u6e90\u4e0a\u5bf9\u6bd4&#xff0c;\u76f4\u89c2\u4f53\u4f1a\u300c\u5355\u5411\u300d\u548c\u300c\u53cc\u5411\u300d\u7684\u5dee\u5f02\u3002<\/p>\n<hr \/>\n<h3>0.2 \u6574\u4f53\u67b6\u6784\u56fe<\/h3>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/08\/20260804081738-6a71a022497a4.png\" alt=\"SSE\u4e0eWebSocket\u67b6\u6784\u56fe\u751f\u6210\" \/><\/p>\n<h3>0.3 \u4e09\u4e2a\u89d2\u8272<\/h3>\n<table>\n<tr>\u89d2\u8272\u6587\u4ef6\u804c\u8d23<\/tr>\n<tbody>\n<tr>\n<td>\u6570\u636e\u5c42<\/td>\n<td>models.py<\/td>\n<td>\u7ba1\u83dc\u5355\u3001\u8ba2\u5355\u3001\u72b6\u6001\u63a8\u8fdb\u3002\u548c\u4f20\u8f93\u5c42\u5b8c\u5168\u89e3\u8026&#xff0c;\u7eaf\u5185\u5b58\u72b6\u6001\u3002<\/td>\n<\/tr>\n<tr>\n<td>\u4f20\u8f93\u5c42<\/td>\n<td>sse.py \/ ws.py<\/td>\n<td>\u5404\u81ea\u7ef4\u62a4\u4e00\u4e2a\u8ba2\u9605\u8005\u96c6\u5408&#xff0c;\u628a\u6570\u636e\u6309\u5404\u81ea\u534f\u8bae\u63a8\u4e0b\u53bb\u3002<\/td>\n<\/tr>\n<tr>\n<td>\u5fc3\u8df3\u6e90<\/td>\n<td>broadcaster.py<\/td>\n<td>\u540e\u53f0\u534f\u7a0b&#xff0c;\u6bcf 0.8s \u8c03\u4e00\u6b21 advance()&#xff0c;\u628a\u7ed3\u679c\u540c\u65f6\u53d1\u7ed9 SSE \u548c WS \u4e24\u4e2a\u96c6\u5408\u3002\u662f\u5b83\u4eec\u5171\u4eab\u7684\u65f6\u949f\u3002<\/td>\n<\/tr>\n<tr>\n<td>\u5165\u53e3<\/td>\n<td>app.py<\/td>\n<td>\u7ec4\u88c5 FastAPI\u3001\u6302\u8def\u7531\u3001\u8d77\u540e\u53f0\u4efb\u52a1\u3001\u6258\u7ba1\u9759\u6001\u9875\u3002<\/td>\n<\/tr>\n<tr>\n<td>\u524d\u7aef<\/td>\n<td>static\/index.html<\/td>\n<td>\u7528 EventSource \u6536 SSE\u3001\u7528 WebSocket \u53d1\u6536\u547d\u4ee4\u3001\u628a\u6570\u636e\u753b\u6210\u5361\u7247\u3002<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>0.4 \u5173\u952e\u6982\u5ff5&#xff1a;SSE vs WebSocket&#xff08;\u5148\u8bb0\u4f4f\u4e00\u53e5\u8bdd&#xff09;<\/h3>\n<ul>\n<li>SSE&#xff1a;\u670d\u52a1\u5668\u2192\u6d4f\u89c8\u5668\u7684\u5355\u5411\u6c34\u7ba1\u3002\u57fa\u4e8e HTTP&#xff0c;\u6d4f\u89c8\u5668\u5f00 EventSource \u5c31\u8fde\u4e0a&#xff0c;\u670d\u52a1\u5668\u7528 text\/event-stream \u4e00\u5e27\u4e00\u5e27\u5730\u63a8\u6587\u672c\u3002\u65ad\u7ebf\u6d4f\u89c8\u5668\u81ea\u52a8\u91cd\u8fde\u3002<\/li>\n<li>WebSocket&#xff1a;\u5168\u53cc\u5de5\u3002\u63e1\u624b\u540e\u5347\u7ea7\u6210 ws:\/\/&#xff0c;\u53cc\u65b9\u90fd\u80fd\u968f\u65f6\u53d1\u6d88\u606f\u3002\u9002\u5408\u6709\u4ea4\u4e92\u7684\u573a\u666f&#xff08;\u53d1\u547d\u4ee4\u3001\u62ff\u56de\u6267&#xff09;\u3002<\/li>\n<\/ul>\n<p>\u672c\u9879\u76ee\u91cc&#xff1a;<\/p>\n<ul>\n<li>\u300c\u770b\u8ba2\u5355\u300d\u7528 SSE\u2014\u2014\u53ea\u9700\u670d\u52a1\u5668\u63a8\u3001\u6d4f\u89c8\u5668\u6536&#xff0c;\u6700\u7b80\u5355&#xff1b;<\/li>\n<li>\u300c\u5e97\u5458\u64cd\u4f5c\u300d\u7528 WS\u2014\u2014\u5e97\u5458\u8981\u53d1\u547d\u4ee4&#xff0c;\u5fc5\u987b\u53cc\u5411\u3002<\/li>\n<\/ul>\n<h3>0.5 \u6570\u636e\u6d41\u52a8&#xff08;\u4e00\u6b21 tick&#xff09;<\/h3>\n<p>broadcaster \u6bcf 0.8s \u89e6\u53d1\u4e00\u6b21:<br \/>\n  1. advance()                 \u2190 models.py \u63a8\u8fdb\u6240\u6709\u8ba2\u5355&#xff0c;\u8fd4\u56de\u5feb\u7167 dict<br \/>\n  2. json.dumps(snapshot)      \u2190 \u5e8f\u5217\u5316\u6210\u5b57\u7b26\u4e32 payload<br \/>\n  3. \u5bf9\u6bcf\u4e2a sse_clients \u91cc\u7684 Queue:<br \/>\n        queue.put({&#034;event&#034;:&#034;orders&#034;, &#034;data&#034;: payload})<br \/>\n     \u2192 sse.py \u7684 event_stream() \u4ece Queue \u53d6\u51fa&#xff0c;\u62fc\u6210 SSE \u5e27 yield \u51fa\u53bb<br \/>\n  4. \u5bf9\u6bcf\u4e2a ws_clients \u91cc\u7684 WebSocket:<br \/>\n        ws.send_text(payload)   \u2190 \u76f4\u63a5\u53d1&#xff0c;\u5931\u8d25\u5219\u4ece\u96c6\u5408\u79fb\u9664<\/p>\n<ul>\n<li>SSE \u7aef&#xff1a;\u6bcf\u4e2a\u8fde\u63a5\u6709\u81ea\u5df1\u7684 Queue&#xff0c;\u5e7f\u64ad\u5668\u53ea\u5f80 Queue \u91cc\u585e&#xff0c;\u4e0d\u76f4\u63a5\u53d1\u2014\u2014\u4fdd\u8bc1\u53d1\u9001\u4e0d\u963b\u585e\u5e7f\u64ad\u5668\u3002<\/li>\n<li>WS \u7aef&#xff1a;\u76f4\u63a5 send_text&#xff0c;\u56e0\u4e3a WS \u539f\u751f\u652f\u6301\u5f02\u6b65\u53d1\u9001\u4e14\u80fd\u611f\u77e5\u8fde\u63a5\u65ad\u5f00\u3002<\/li>\n<\/ul>\n<h3>0.6 \u8fd0\u884c\u6548\u679c<\/h3>\n<p>\u542f\u52a8\u670d\u52a1\u3001\u6253\u5f00 http:\/\/127.0.0.1:8000\/ \u540e&#xff0c;\u4f60\u4f1a\u770b\u5230&#xff1a;<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/08\/20260804081737-6a71a021780c1.png\" alt=\"\u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f\u8fd0\u884c\u622a\u56fe\" \/><\/p>\n<ul>\n<li>\u9876\u90e8&#xff1a;\u6807\u9898 &#043; SSE\/WS \u8fde\u63a5\u72b6\u6001\u706f &#043; \u5b9e\u65f6\u65f6\u949f&#xff1b;<\/li>\n<li>\u7edf\u8ba1\u6761&#xff1a;\u603b\u8ba2\u5355 \/ \u5236\u4f5c\u4e2d \/ \u5df2\u5b8c\u6210 \/ \u5df2\u53d6\u9910&#xff1b;<\/li>\n<li>\u5de6\u4fa7 &#x1f4cb; \u5b9e\u65f6\u8ba2\u5355&#xff08;\u6807\u7b7e\u300cSSE \u5355\u5411\u63a8\u9001\u300d&#xff09;&#xff1a;\u6bcf 0.8s \u5237\u65b0\u7684\u8ba2\u5355\u5361\u7247&#xff0c;\u5e26\u8fdb\u5ea6\u6761\u548c\u72b6\u6001\u8272\u5757&#xff1b;<\/li>\n<li>\u53f3\u4fa7 &#x1f39b;\ufe0f \u5e97\u5458\u64cd\u4f5c\u53f0&#xff08;\u6807\u7b7e\u300cWebSocket \u53cc\u5411\u901a\u9053\u300d&#xff09;&#xff1a;\u540c\u6837\u7684\u8ba2\u5355\u5361\u7247 &#043; \u547d\u4ee4\u8f93\u5165\u6846 &#043; ping\/add\/snapshot \u6309\u94ae &#043; \u9ed1\u5e95\u901a\u4fe1\u65e5\u5fd7\u3002<\/li>\n<\/ul>\n<p>\u5728\u53f3\u4fa7\u64cd\u4f5c\u53f0\u70b9\u51e0\u4e0b\u6309\u94ae&#xff0c;\u4f1a\u770b\u5230 WS \u901a\u4fe1\u65e5\u5fd7\u91cc\u51fa\u73b0 \u2192 \u53d1\u51fa\u7684\u547d\u4ee4 \u548c \u2190 \u6536\u5230\u7684\u56de\u6267&#xff0c;\u8ba2\u5355\u4e5f\u4f1a\u5b9e\u65f6\u53d8\u5316&#xff1a;<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/08\/20260804081737-6a71a021e51d4.png\" alt=\"WebSocket \u64cd\u4f5c\u53f0\u4e0e\u901a\u4fe1\u65e5\u5fd7\" \/><\/p>\n<hr \/>\n<h3>0.7 \u9605\u8bfb\u5efa\u8bae<\/h3>\n<ul>\n<li>\u5982\u679c\u4f60\u662f\u521d\u5b66\u8005&#xff1a;\u4e25\u683c\u6309\u7ae0\u8282\u987a\u5e8f&#xff0c;\u6bcf\u7ae0\u5148\u6284\u4ee3\u7801\u3001\u518d\u770b\u8bb2\u89e3\u3001\u518d\u9a8c\u8bc1\u3002<\/li>\n<li>\u5982\u679c\u4f60\u5df2\u7ecf\u4f1a FastAPI&#xff1a;\u53ef\u4ee5\u76f4\u63a5\u8df3\u5230\u7b2c 3\u30014 \u7ae0\u770b SSE\/WS \u4e24\u4e2a\u4f20\u8f93\u6a21\u5757\u7684\u5b9e\u73b0\u5dee\u5f02&#xff0c;\u518d\u770b\u7b2c 5 \u7ae0\u5e7f\u64ad\u5668\u600e\u4e48\u628a\u5b83\u4eec\u4e32\u8d77\u6765\u3002<\/li>\n<li>\u7b2c 9 \u7ae0\u662f\u5bf9\u6bd4\u603b\u7ed3 &#043; \u6269\u5c55\u7ec3\u4e60&#xff0c;\u5168\u90e8\u5199\u5b8c\u540e\u56de\u5934\u770b&#xff0c;\u4f1a\u6709\u66f4\u6df1\u7406\u89e3\u3002<\/li>\n<\/ul>\n<p>\u4e0b\u4e00\u7ae0 \u2192 01-\u73af\u5883\u4e0e\u9879\u76ee\u9aa8\u67b6.md&#xff1a;\u88c5\u73af\u5883\u3001\u5efa\u76ee\u5f55\u3001\u5199\u914d\u7f6e\u6587\u4ef6\u3002<\/p>\n<hr \/>\n<h2>\u7b2c 1 \u7ae0 \u00b7 \u73af\u5883\u4e0e\u9879\u76ee\u9aa8\u67b6<\/h2>\n<h3>\u672c\u7ae0\u76ee\u6807<\/h3>\n<p>\u628a\u5f00\u53d1\u73af\u5883\u88c5\u597d\u3001\u628a\u9879\u76ee\u76ee\u5f55\u548c\u914d\u7f6e\u6587\u4ef6\u5efa\u597d\u3002\u8fd9\u4e00\u7ae0\u4e0d\u5199\u4e1a\u52a1\u903b\u8f91&#xff0c;\u4f46\u5b83\u662f\u540e\u9762\u6240\u6709\u4ee3\u7801\u7684\u300c\u5730\u57fa\u300d\u3002<\/p>\n<p>\u5b66\u5b8c\u672c\u7ae0\u4f60\u4f1a\u6709\u8fd9\u4e9b\u6587\u4ef6&#xff08;\u5168\u662f\u914d\u7f6e\/\u7a7a\u58f3&#xff09;&#xff1a;<\/p>\n<p>fastapi-sse-ws-\u5976\u8336\u770b\u677f\/<br \/>\n\u251c\u2500\u2500 pyproject.toml<br \/>\n\u251c\u2500\u2500 .python-version<br \/>\n\u251c\u2500\u2500 .gitignore<br \/>\n\u251c\u2500\u2500 src\/<br \/>\n\u2502   \u2514\u2500\u2500 __init__.py<br \/>\n\u2514\u2500\u2500 static\/        # \u7a7a\u76ee\u5f55&#xff0c;\u7b2c 7 \u7ae0\u653e index.html<\/p>\n<hr \/>\n<h3>1.1 \u51c6\u5907 Python \u73af\u5883<\/h3>\n<p>\u672c\u9879\u76ee\u7528 Python 3.14\u3002\u5148\u786e\u8ba4\u4f60\u88c5\u4e86 Python 3.14&#xff1a;<\/p>\n<p>python <span class=\"token parameter variable\">&#8211;version<\/span><br \/>\n<span class=\"token comment\"># \u5e94\u8f93\u51fa\u7c7b\u4f3c: Python 3.14.x<\/span><\/p>\n<p>\u5982\u679c\u6ca1\u88c5&#xff0c;\u53bb python.org \u4e0b\u8f7d\u5b89\u88c5\u3002<\/p>\n<h3>1.2 \u5b89\u88c5 uv&#xff08;\u63a8\u8350&#xff09;<\/h3>\n<p>uv \u662f\u4e00\u4e2a\u8d85\u5feb\u7684 Python \u5305\u7ba1\u7406\u5668&#xff0c;\u6bd4 pip \u5feb\u5f88\u591a\u3002\u88c5\u4e00\u6b21\u5373\u53ef&#xff1a;<\/p>\n<p><span class=\"token comment\"># macOS \/ Linux<\/span><br \/>\n<span class=\"token function\">curl<\/span> <span class=\"token parameter variable\">-LsSf<\/span> https:\/\/astral.sh\/uv\/install.sh <span class=\"token operator\">|<\/span> <span class=\"token function\">sh<\/span><\/p>\n<p><span class=\"token comment\"># Windows (PowerShell)<\/span><br \/>\npowershell <span class=\"token parameter variable\">-ExecutionPolicy<\/span> ByPass <span class=\"token parameter variable\">-c<\/span> <span class=\"token string\">&#034;irm https:\/\/astral.sh\/uv\/install.ps1 | iex&#034;<\/span><\/p>\n<p><span class=\"token comment\"># \u6216\u7528 pip \u88c5\u4e5f\u884c<\/span><br \/>\npip <span class=\"token function\">install<\/span> uv<\/p>\n<p>\u9a8c\u8bc1&#xff1a;<\/p>\n<p>uv <span class=\"token parameter variable\">&#8211;version<\/span><br \/>\n<span class=\"token comment\"># \u5e94\u8f93\u51fa: uv 0.11.x &#8230;<\/span><\/p>\n<p>\u6ca1 uv \u4e5f\u80fd\u5b66&#xff1a;\u540e\u9762\u6240\u6709 uv xxx \u547d\u4ee4\u90fd\u7ed9\u51fa\u5bf9\u5e94\u7684 pip \u7248\u672c\u3002\u7528 uv \u53ea\u662f\u66f4\u5feb\u3001\u66f4\u7701\u5fc3\u3002<\/p>\n<h3>1.3 \u521b\u5efa\u9879\u76ee\u76ee\u5f55<\/h3>\n<p><span class=\"token function\">mkdir<\/span> fastapi-sse-ws-\u5976\u8336\u770b\u677f<br \/>\n<span class=\"token builtin class-name\">cd<\/span> fastapi-sse-ws-\u5976\u8336\u770b\u677f<\/p>\n<h3>1.4 .python-version \u2014\u2014 \u56fa\u5b9a Python \u7248\u672c<\/h3>\n<h4>\u539f\u59cb\u5b8c\u6574\u4ee3\u7801<\/h4>\n<p>\u65b0\u5efa\u6587\u4ef6 .python-version&#xff0c;\u5185\u5bb9\u53ea\u6709\u4e00\u884c&#xff1a;<\/p>\n<p>3.14<\/p>\n<h4>\u8bb2\u89e3<\/h4>\n<ul>\n<li>\u8fd9\u4e2a\u6587\u4ef6\u88ab uv\u3001pyenv \u7b49\u5de5\u5177\u8bc6\u522b&#xff0c;\u8868\u793a\u300c\u8fd9\u4e2a\u9879\u76ee\u7528 Python 3.14\u300d&#xff1b;<\/li>\n<li>\u56e2\u961f\u534f\u4f5c\u65f6&#xff0c;\u5927\u5bb6 uv sync \u5c31\u4f1a\u81ea\u52a8\u88c5\u5bf9\u5e94\u7248\u672c&#xff0c;\u4e0d\u7528\u53e3\u5934\u7ea6\u5b9a&#xff1b;<\/li>\n<li>\u5185\u5bb9\u5c31\u662f 3.14&#xff0c;\u4e0d\u5e26\u5c0f\u7248\u672c\u53f7&#xff0c;\u8868\u793a\u300c3.14.x \u90fd\u884c\u300d\u3002<\/li>\n<\/ul>\n<h3>1.5 pyproject.toml \u2014\u2014 \u9879\u76ee\u5143\u4fe1\u606f &#043; \u4f9d\u8d56<\/h3>\n<h4>\u539f\u59cb\u5b8c\u6574\u4ee3\u7801<\/h4>\n<p>\u65b0\u5efa\u6587\u4ef6 pyproject.toml&#xff1a;<\/p>\n<p>[project]<br \/>\nname &#061; &#034;fastapi-sse-ws&#034;<br \/>\nversion &#061; &#034;0.1.0&#034;<br \/>\ndescription &#061; &#034;Add your description here&#034;<br \/>\nrequires-python &#061; &#034;&gt;&#061;3.14&#034;<br \/>\ndependencies &#061; [<br \/>\n    &#034;fastapi&gt;&#061;0.141.1&#034;,<br \/>\n    &#034;uvicorn[standard]&gt;&#061;0.52.1&#034;,<br \/>\n    &#034;websockets&gt;&#061;17.0.1&#034;,<br \/>\n]<\/p>\n<h4>\u8bb2\u89e3<\/h4>\n<ul>\n<li>[project]&#xff1a;\u73b0\u4ee3 Python \u9879\u76ee\u7684\u6807\u51c6\u5143\u4fe1\u606f\u6bb5&#xff08;PEP 621&#xff09;&#xff1b;<\/li>\n<li>name \/ version&#xff1a;\u9879\u76ee\u540d\u548c\u7248\u672c&#xff0c;uv \/ pip \u90fd\u4f1a\u7528\u5b83\u751f\u6210\u5305\u4fe1\u606f&#xff1b;<\/li>\n<li>requires-python &#061; &#034;&gt;&#061;3.14&#034;&#xff1a;\u672c\u9879\u76ee\u7528\u5230\u4e86 3.14 \u7684\u7279\u6027&#xff08;\u5982 datetime.UTC \u522b\u540d&#xff09;&#xff0c;\u6240\u4ee5\u8981\u6c42 3.14&#043;&#xff1b;<\/li>\n<li>dependencies \u4e09\u4e2a\u4f9d\u8d56&#xff1a;\n<ul>\n<li>fastapi&#xff1a;Web \u6846\u67b6&#xff0c;\u63d0\u4f9b\u8def\u7531\u3001StreamingResponse\u3001WebSocket \u7b49&#xff1b;<\/li>\n<li>uvicorn[standard]&#xff1a;ASGI \u670d\u52a1\u5668\u3002[standard] \u8868\u793a\u88c5\u300c\u5e26\u989d\u5916\u6027\u80fd\u4f18\u5316\u300d\u7684\u7248\u672c&#xff08;\u542b uvloop\u3001httptools \u7b49&#xff09;&#xff1b;<\/li>\n<li>websockets&#xff1a;WebSocket \u534f\u8bae\u5e93&#xff0c;Uvicorn \u5904\u7406 WS \u65f6\u9700\u8981\u5b83\u3002<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u4e3a\u4ec0\u4e48 FastAPI \u4e0d\u81ea\u52a8\u5e26 websockets&#xff1f;\u56e0\u4e3a\u5f88\u591a\u9879\u76ee\u7528\u4e0d\u5230 WS\u3002uvicorn[standard] \u5df2\u7ecf\u628a websockets \u4f5c\u4e3a\u53ef\u9009\u4f9d\u8d56\u88c5\u4e0a\u4e86&#xff0c;\u8fd9\u91cc\u663e\u5f0f\u58f0\u660e\u662f\u6559\u5b66\u6e05\u6670\u8d77\u89c1\u3002<\/p>\n<h3>1.6 \u5b89\u88c5\u4f9d\u8d56<\/h3>\n<p><span class=\"token comment\"># \u7528 uv&#xff08;\u63a8\u8350&#xff09;&#xff1a;\u4f1a\u6839\u636e pyproject.toml &#043; .python-version \u81ea\u52a8\u5efa\u865a\u62df\u73af\u5883\u5e76\u88c5\u4f9d\u8d56<\/span><br \/>\nuv <span class=\"token function\">sync<\/span><\/p>\n<p><span class=\"token comment\"># \u4e5f\u53ef\u4ee5\u76f4\u63a5\u7528 pip&#xff08;\u9700\u8981\u81ea\u5df1\u5148 python -m venv .venv \u5e76\u6fc0\u6d3b&#xff09;<\/span><br \/>\npip <span class=\"token function\">install<\/span> fastapi <span class=\"token string\">&#034;uvicorn[standard]&#034;<\/span> websockets<\/p>\n<p>uv sync \u6267\u884c\u5b8c\u540e&#xff0c;\u76ee\u5f55\u91cc\u4f1a\u591a\u51fa .venv\/&#xff08;\u865a\u62df\u73af\u5883&#xff09;\u548c uv.lock&#xff08;\u9501\u6587\u4ef6&#xff0c;\u8bb0\u5f55\u7cbe\u786e\u7248\u672c&#xff09;\u3002<\/p>\n<h3>1.7 .gitignore \u2014\u2014 \u4e0d\u63d0\u4ea4\u7684\u4e1c\u897f<\/h3>\n<h4>\u539f\u59cb\u5b8c\u6574\u4ee3\u7801<\/h4>\n<p>\u65b0\u5efa\u6587\u4ef6 .gitignore&#xff1a;<\/p>\n<p># Python-generated files<br \/>\n__pycache__\/<br \/>\n*.py[oc]<br \/>\nbuild\/<br \/>\ndist\/<br \/>\nwheels\/<br \/>\n*.egg-info<\/p>\n<p># Virtual environments<br \/>\n.venv<\/p>\n<h4>\u8bb2\u89e3<\/h4>\n<ul>\n<li>__pycache__\/\u3001*.py[oc]&#xff1a;Python \u8fd0\u884c\u65f6\u751f\u6210\u7684\u5b57\u8282\u7801\u7f13\u5b58&#xff0c;\u6ca1\u5fc5\u8981\u8fdb\u7248\u672c\u5e93&#xff1b;<\/li>\n<li>build\/ dist\/ wheels\/ *.egg-info&#xff1a;\u6253\u5305\u4ea7\u7269&#xff1b;<\/li>\n<li>.venv&#xff1a;\u865a\u62df\u73af\u5883\u76ee\u5f55&#xff0c;\u6bcf\u4e2a\u4eba\u672c\u5730\u4e00\u4efd&#xff0c;\u4e0d\u8fdb\u7248\u672c\u5e93\u3002<\/li>\n<\/ul>\n<h3>1.8 src\/__init__.py \u2014\u2014 \u628a src \u53d8\u6210\u5305<\/h3>\n<h4>\u539f\u59cb\u5b8c\u6574\u4ee3\u7801<\/h4>\n<p>\u65b0\u5efa\u76ee\u5f55 src\/&#xff0c;\u91cc\u9762\u5efa\u7a7a\u6587\u4ef6 __init__.py&#xff1a;<\/p>\n<p><span class=\"token triple-quoted-string string\">&#034;&#034;&#034;src \u5305: \u6559\u5b66\u6a21\u5757\u96c6\u5408.&#034;&#034;&#034;<\/span><\/p>\n<h4>\u8bb2\u89e3<\/h4>\n<ul>\n<li>\u6709 __init__.py \u7684\u76ee\u5f55&#xff0c;Python \u624d\u628a\u5b83\u5f53\u6210\u4e00\u4e2a\u5305&#xff0c;\u91cc\u9762\u7684\u6a21\u5757\u624d\u80fd\u7528 from src.app import app \u8fd9\u79cd\u65b9\u5f0f\u5bfc\u5165&#xff1b;<\/li>\n<li>\u8fd9\u4e00\u884c docstring \u662f\u5305\u7684\u8bf4\u660e&#xff0c;\u8fd0\u884c help(src) \u65f6\u4f1a\u663e\u793a&#xff1b;<\/li>\n<li>\u540e\u9762\u6211\u4eec\u8981\u5199\u7684 app.py models.py sse.py ws.py broadcaster.py \u90fd\u653e\u5728 src\/ \u4e0b&#xff0c;\u5b83\u4eec\u4e4b\u95f4\u7528 from .models import &#8230; \u8fd9\u79cd\u76f8\u5bf9\u5bfc\u5165\u4e92\u76f8\u5f15\u7528\u3002<\/li>\n<\/ul>\n<h3>1.9 \u5efa static\/ \u76ee\u5f55<\/h3>\n<p><span class=\"token function\">mkdir<\/span> static<\/p>\n<p>\u6682\u65f6\u7559\u7a7a&#xff0c;\u7b2c 7 \u7ae0\u5f80\u91cc\u653e index.html\u3002<\/p>\n<p>static\/ \u76ee\u5f55\u5728 app.py \u91cc\u4f1a\u88ab\u6302\u8f7d\u6210\u9759\u6001\u8d44\u6e90&#xff0c;\u6d4f\u89c8\u5668\u8bbf\u95ee \/static\/xxx \u5c31\u80fd\u62ff\u5230\u91cc\u9762\u7684\u6587\u4ef6\u3002<\/p>\n<h3>1.10 \u73b0\u5728\u7684\u76ee\u5f55\u7ed3\u6784<\/h3>\n<p>fastapi-sse-ws-\u5976\u8336\u770b\u677f\/<br \/>\n\u251c\u2500\u2500 .gitignore<br \/>\n\u251c\u2500\u2500 .python-version<br \/>\n\u251c\u2500\u2500 pyproject.toml<br \/>\n\u251c\u2500\u2500 uv.lock            # uv sync \u81ea\u52a8\u751f\u6210&#xff08;\u7528 pip \u65f6\u6ca1\u6709&#xff09;<br \/>\n\u251c\u2500\u2500 .venv\/             # uv sync \u81ea\u52a8\u751f\u6210&#xff08;\u7528 pip \u65f6\u9700\u624b\u52a8\u5efa&#xff09;<br \/>\n\u251c\u2500\u2500 src\/<br \/>\n\u2502   \u2514\u2500\u2500 __init__.py<br \/>\n\u2514\u2500\u2500 static\/            # \u7a7a\u76ee\u5f55<\/p>\n<h3>1.11 \u52a8\u624b\u9a8c\u8bc1<\/h3>\n<p><span class=\"token comment\"># \u5728\u9879\u76ee\u6839\u76ee\u5f55\u6267\u884c&#xff0c;\u786e\u8ba4\u4f9d\u8d56\u88c5\u597d\u4e86<\/span><br \/>\nuv run python <span class=\"token parameter variable\">-c<\/span> <span class=\"token string\">&#034;import fastapi, uvicorn, websockets; print(&#039;OK&#039;)&#034;<\/span><br \/>\n<span class=\"token comment\"># \u7528 pip \u7684\u8bdd: python -c &#034;import fastapi, uvicorn, websockets; print(&#039;OK&#039;)&#034;<\/span><\/p>\n<p><span class=\"token comment\"># \u671f\u671b\u8f93\u51fa:<\/span><br \/>\n<span class=\"token comment\"># OK<\/span><\/p>\n<p>\u5982\u679c\u8f93\u51fa OK&#xff0c;\u8bf4\u660e\u5730\u57fa\u6253\u597d\u4e86\u3002\u4e0b\u4e00\u7ae0\u6211\u4eec\u5f80 src\/ \u91cc\u5199\u7b2c\u4e00\u4e2a\u4e1a\u52a1\u6587\u4ef6&#xff1a;\u6570\u636e\u5c42 models.py\u3002<\/p>\n<hr \/>\n<p>\u4e0b\u4e00\u7ae0 \u2192 02-\u6570\u636e\u5c42-models.md&#xff1a;\u83dc\u5355\u3001\u8ba2\u5355\u7c7b\u578b\u3001\u72b6\u6001\u63a8\u8fdb\u903b\u8f91\u3002<\/p>\n<hr \/>\n<h2>\u7b2c 2 \u7ae0 \u00b7 \u6570\u636e\u5c42 models.py<\/h2>\n<h3>\u672c\u7ae0\u76ee\u6807<\/h3>\n<p>\u5199\u9879\u76ee\u7684\u300c\u5927\u8111\u300d\u2014\u2014\u6570\u636e\u5c42\u3002\u8fd9\u4e00\u5c42\u8d1f\u8d23&#xff1a;<\/p>\n<ul>\n<li>\u5b9a\u4e49\u83dc\u5355\u3001\u53e3\u5473\u9009\u9879&#xff1b;<\/li>\n<li>\u5b9a\u4e49\u8ba2\u5355&#xff08;Order&#xff09;\u548c\u5feb\u7167&#xff08;Snapshot&#xff09;\u7684\u7c7b\u578b&#xff1b;<\/li>\n<li>\u7ef4\u62a4\u6240\u6709\u8ba2\u5355\u7684\u5185\u5b58\u72b6\u6001&#xff1b;<\/li>\n<li>\u63d0\u4f9b advance()&#xff1a;\u6bcf\u88ab\u8c03\u7528\u4e00\u6b21&#xff0c;\u5c31\u628a\u6240\u6709\u8ba2\u5355\u5f80\u524d\u63a8\u8fdb\u4e00\u6b65&#xff0c;\u5e76\u968f\u673a\u751f\u6210\u65b0\u8ba2\u5355\u3002<\/li>\n<\/ul>\n<p>\u5173\u952e\u8bbe\u8ba1&#xff1a;\u6570\u636e\u5c42\u5b8c\u5168\u4e0d\u77e5\u9053 SSE \/ WebSocket \u7684\u5b58\u5728\u3002\u5b83\u53ea\u7ba1\u6570\u636e&#xff0c;\u8c01\u8981\u63a8\u6570\u636e\u8c01\u81ea\u5df1\u53bb\u62ff\u3002\u8fd9\u6837\u540e\u9762\u8bb2\u4e24\u79cd\u4f20\u8f93\u534f\u8bae\u65f6&#xff0c;\u6570\u636e\u5c42\u4e00\u884c\u90fd\u4e0d\u7528\u6539\u3002<\/p>\n<hr \/>\n<h3>2.1 \u539f\u59cb\u5b8c\u6574\u4ee3\u7801<\/h3>\n<p>\u65b0\u5efa\u6587\u4ef6 src\/models.py&#xff0c;\u5b8c\u6574\u7167\u6284&#xff1a;<\/p>\n<p><span class=\"token triple-quoted-string string\">&#034;&#034;&#034;<br \/>\n\u6570\u636e\u5c42: \u83dc\u5355\u3001\u8ba2\u5355\u72b6\u6001\u3001\u63a8\u8fdb\u903b\u8f91.<\/p>\n<p>\u4e0e\u4f20\u8f93\u5c42(SSE \/ WebSocket)\u89e3\u8026, \u65b9\u4fbf\u5355\u72ec\u8bb2\u89e3\u72b6\u6001\u7ba1\u7406.<br \/>\n&#034;&#034;&#034;<\/span><\/p>\n<p><span class=\"token keyword\">import<\/span> random<br \/>\n<span class=\"token keyword\">from<\/span> datetime <span class=\"token keyword\">import<\/span> UTC<span class=\"token punctuation\">,<\/span> datetime<br \/>\n<span class=\"token keyword\">from<\/span> itertools <span class=\"token keyword\">import<\/span> count<br \/>\n<span class=\"token keyword\">from<\/span> typing <span class=\"token keyword\">import<\/span> TypedDict<\/p>\n<p><span class=\"token comment\"># &#8212;&#8212;&#8212;- \u83dc\u5355\u4e0e\u53e3\u5473 &#8212;&#8212;&#8212;-<\/span><\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">MenuItem<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    name<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    base<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    price<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">int<\/span><\/p>\n<p>MENU<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span>MenuItem<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><br \/>\n    <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u73cd\u73e0\u5976\u8336&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;base&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u7ea2\u8336&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;price&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">12<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u6768\u679d\u7518\u9732&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;base&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u8292\u679c&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;price&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">18<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u828b\u6ce5\u5575\u5575&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;base&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u4e4c\u9f99&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;price&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">15<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u67e0\u6aac\u517b\u4e50\u591a&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;base&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u7eff\u8336&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;price&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">13<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u8349\u8393\u5976\u76d6&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;base&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u8309\u8389&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;price&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">16<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u8584\u8377\u51b0\u53ef\u53ef&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;base&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;\u53ef\u53ef&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;price&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">14<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span><br \/>\n<span class=\"token punctuation\">]<\/span><br \/>\nSUGAR <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;\u5168\u7cd6&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e03\u5206&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u534a\u7cd6&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e09\u5206&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u65e0\u7cd6&#034;<\/span><span class=\"token punctuation\">]<\/span><br \/>\nICE <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;\u6b63\u5e38\u51b0&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5c11\u51b0&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u53bb\u51b0&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u70ed\u996e&#034;<\/span><span class=\"token punctuation\">]<\/span><br \/>\nTOPPING <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;\u73cd\u73e0&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u6930\u679c&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5e03\u4e01&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u828b\u5706&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5976\u76d6&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e0d\u52a0\u6599&#034;<\/span><span class=\"token punctuation\">]<\/span><\/p>\n<p>STATUSES <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;\u5f85\u5236\u4f5c&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5236\u4f5c\u4e2d&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5df2\u5b8c\u6210&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5df2\u53d6\u9910&#034;<\/span><span class=\"token punctuation\">]<\/span><\/p>\n<p><span class=\"token comment\"># &#8212;&#8212;&#8212;- \u7c7b\u578b\u5b9a\u4e49 &#8212;&#8212;&#8212;-<\/span><\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">Order<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">,<\/span> total<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u8ba2\u5355\u7ed3\u6784. total&#061;False \u56e0\u4e3a ready_since \u4ec5\u5728\u5236\u4f5c\u5b8c\u6210\u540e\u624d\u5b58\u5728.&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token builtin\">id<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">int<\/span><br \/>\n    drink<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    base<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    price<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">int<\/span><br \/>\n    sugar<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    ice<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    topping<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    status<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    progress<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">int<\/span><br \/>\n    created_at<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    ready_since<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">int<\/span><\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">Snapshot<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    time<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    orders<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span>Order<span class=\"token punctuation\">]<\/span><\/p>\n<p><span class=\"token comment\"># &#8212;&#8212;&#8212;- \u5171\u4eab\u72b6\u6001 &#8212;&#8212;&#8212;-<\/span><\/p>\n<p>order_seq <span class=\"token operator\">&#061;<\/span> count<span class=\"token punctuation\">(<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span>                       <span class=\"token comment\"># \u8ba2\u5355\u53f7\u81ea\u589e\u5668<\/span><br \/>\norders<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">dict<\/span><span class=\"token punctuation\">[<\/span><span class=\"token builtin\">int<\/span><span class=\"token punctuation\">,<\/span> Order<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">}<\/span>              <span class=\"token comment\"># order_id -&gt; order \u8be6\u60c5<\/span><\/p>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">now_iso<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;ISO8601 \u65f6\u95f4\u6233 (Python 3.14 \u63a8\u8350\u7528 UTC \u522b\u540d, \u907f\u514d\u5e9f\u5f03\u7684 utcnow()).&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token keyword\">return<\/span> datetime<span class=\"token punctuation\">.<\/span>now<span class=\"token punctuation\">(<\/span>UTC<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>isoformat<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">new_order<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> Order<span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u968f\u673a\u751f\u6210\u4e00\u4efd\u65b0\u8ba2\u5355.&#034;&#034;&#034;<\/span><br \/>\n    m <span class=\"token operator\">&#061;<\/span> random<span class=\"token punctuation\">.<\/span>choice<span class=\"token punctuation\">(<\/span>MENU<span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">return<\/span> Order<span class=\"token punctuation\">(<\/span><br \/>\n        <span class=\"token builtin\">id<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token builtin\">next<\/span><span class=\"token punctuation\">(<\/span>order_seq<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        drink<span class=\"token operator\">&#061;<\/span>m<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        base<span class=\"token operator\">&#061;<\/span>m<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;base&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        price<span class=\"token operator\">&#061;<\/span>m<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;price&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        sugar<span class=\"token operator\">&#061;<\/span>random<span class=\"token punctuation\">.<\/span>choice<span class=\"token punctuation\">(<\/span>SUGAR<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        ice<span class=\"token operator\">&#061;<\/span>random<span class=\"token punctuation\">.<\/span>choice<span class=\"token punctuation\">(<\/span>ICE<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        topping<span class=\"token operator\">&#061;<\/span>random<span class=\"token punctuation\">.<\/span>choice<span class=\"token punctuation\">(<\/span>TOPPING<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        status<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;\u5f85\u5236\u4f5c&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        progress<span class=\"token operator\">&#061;<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        created_at<span class=\"token operator\">&#061;<\/span>now_iso<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    <span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">advance<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> Snapshot<span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u63a8\u8fdb\u6240\u6709\u672a\u5b8c\u6210\u8ba2\u5355, \u8fd4\u56de\u6700\u65b0\u5feb\u7167 (\u6309 id \u5012\u5e8f).&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token comment\"># 1) \u5076\u5c14(20% \u6982\u7387)\u751f\u6210\u65b0\u8ba2\u5355<\/span><br \/>\n    <span class=\"token keyword\">if<\/span> random<span class=\"token punctuation\">.<\/span>random<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&lt;<\/span> <span class=\"token number\">0.2<\/span> <span class=\"token keyword\">or<\/span> <span class=\"token keyword\">not<\/span> orders<span class=\"token punctuation\">:<\/span><br \/>\n        o <span class=\"token operator\">&#061;<\/span> new_order<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        orders<span class=\"token punctuation\">[<\/span>o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;id&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> o<\/p>\n<p>    <span class=\"token comment\"># 2) \u63a8\u8fdb\u8fdb\u5ea6<\/span><br \/>\n    completed<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span><span class=\"token builtin\">int<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\n    <span class=\"token keyword\">for<\/span> oid<span class=\"token punctuation\">,<\/span> o <span class=\"token keyword\">in<\/span> orders<span class=\"token punctuation\">.<\/span>items<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u53d6\u9910&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">continue<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;\u5f85\u5236\u4f5c&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u5236\u4f5c\u4e2d&#034;<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;\u5236\u4f5c\u4e2d&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;progress&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">min<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">100<\/span><span class=\"token punctuation\">,<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;progress&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#043;<\/span> random<span class=\"token punctuation\">.<\/span>randint<span class=\"token punctuation\">(<\/span><span class=\"token number\">8<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">18<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;progress&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&gt;&#061;<\/span> <span class=\"token number\">100<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u5b8c\u6210&#034;<\/span><br \/>\n        <span class=\"token comment\"># \u5df2\u5b8c\u6210 3 \u4e2a tick \u540e\u81ea\u52a8\u51fa\u961f<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u5b8c\u6210&#034;<\/span> <span class=\"token keyword\">and<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;progress&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&gt;&#061;<\/span> <span class=\"token number\">100<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;ready_since&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> o<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;ready_since&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#043;<\/span> <span class=\"token number\">1<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;ready_since&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&gt;&#061;<\/span> <span class=\"token number\">3<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                completed<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span>oid<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">for<\/span> oid <span class=\"token keyword\">in<\/span> completed<span class=\"token punctuation\">:<\/span><br \/>\n        orders<span class=\"token punctuation\">[<\/span>oid<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u53d6\u9910&#034;<\/span><\/p>\n<p>    <span class=\"token comment\"># 3) \u961f\u5217\u6700\u591a\u4fdd\u7559 8 \u6761\u5df2\u53d6\u9910<\/span><br \/>\n    finished <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span>oid <span class=\"token keyword\">for<\/span> oid<span class=\"token punctuation\">,<\/span> o <span class=\"token keyword\">in<\/span> orders<span class=\"token punctuation\">.<\/span>items<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u53d6\u9910&#034;<\/span><span class=\"token punctuation\">]<\/span><br \/>\n    <span class=\"token keyword\">for<\/span> oid <span class=\"token keyword\">in<\/span> finished<span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">:<\/span><span class=\"token operator\">&#8211;<\/span><span class=\"token number\">8<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token keyword\">if<\/span> <span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>finished<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&gt;<\/span> <span class=\"token number\">8<\/span> <span class=\"token keyword\">else<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        orders<span class=\"token punctuation\">.<\/span>pop<span class=\"token punctuation\">(<\/span>oid<span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">None<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">return<\/span> Snapshot<span class=\"token punctuation\">(<\/span>time<span class=\"token operator\">&#061;<\/span>now_iso<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> orders<span class=\"token operator\">&#061;<\/span><span class=\"token builtin\">sorted<\/span><span class=\"token punctuation\">(<\/span>orders<span class=\"token punctuation\">.<\/span>values<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> key<span class=\"token operator\">&#061;<\/span><span class=\"token keyword\">lambda<\/span> o<span class=\"token punctuation\">:<\/span> <span class=\"token operator\">&#8211;<\/span>o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;id&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">snapshot<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> Snapshot<span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u8fd4\u56de\u5f53\u524d\u5feb\u7167, \u4e0d\u6539\u53d8\u72b6\u6001.&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token keyword\">return<\/span> Snapshot<span class=\"token punctuation\">(<\/span>time<span class=\"token operator\">&#061;<\/span>now_iso<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> orders<span class=\"token operator\">&#061;<\/span><span class=\"token builtin\">sorted<\/span><span class=\"token punctuation\">(<\/span>orders<span class=\"token punctuation\">.<\/span>values<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> key<span class=\"token operator\">&#061;<\/span><span class=\"token keyword\">lambda<\/span> o<span class=\"token punctuation\">:<\/span> <span class=\"token operator\">&#8211;<\/span>o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;id&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>\u26a0\ufe0f \u6284\u5b8c\u5148\u4e0d\u8981\u8fd0\u884c\u2014\u2014advance() \u91cc\u7528\u5230 orders&#xff0c;\u4f46\u76ee\u524d\u6ca1\u4eba\u8c03\u7528\u5b83\u3002\u4e0b\u4e00\u7ae0\u88c5\u597d\u8def\u7531\u3001\u7b2c 5 \u7ae0\u88c5\u597d\u5e7f\u64ad\u5668\u624d\u4f1a\u8dd1\u8d77\u6765\u3002<\/p>\n<hr \/>\n<h3>2.2 \u9010\u6bb5\u8bb2\u89e3<\/h3>\n<h4>2.2.1 \u5bfc\u5165\u4e0e\u80cc\u666f<\/h4>\n<p><span class=\"token keyword\">import<\/span> random<br \/>\n<span class=\"token keyword\">from<\/span> datetime <span class=\"token keyword\">import<\/span> UTC<span class=\"token punctuation\">,<\/span> datetime<br \/>\n<span class=\"token keyword\">from<\/span> itertools <span class=\"token keyword\">import<\/span> count<br \/>\n<span class=\"token keyword\">from<\/span> typing <span class=\"token keyword\">import<\/span> TypedDict<\/p>\n<ul>\n<li>random&#xff1a;\u751f\u6210\u65b0\u8ba2\u5355\u3001\u968f\u673a\u8fdb\u5ea6\u589e\u91cf&#xff1b;<\/li>\n<li>datetime.UTC\u3001datetime&#xff1a;\u751f\u6210\u65f6\u95f4\u6233\u3002\u6ce8\u610f UTC&#xff1a;Python 3.12&#043; \u624d\u6709 datetime.UTC \u5e38\u91cf&#xff08;3.14 \u63a8\u8350\u7528&#xff09;&#xff0c;\u8001\u7684 datetime.utcnow() \u5df2\u5e9f\u5f03&#xff08;\u65f6\u533a\u4e0d\u660e\u786e&#xff09;&#xff1b;<\/li>\n<li>itertools.count&#xff1a;\u4e00\u4e2a\u65e0\u9650\u81ea\u589e\u8ba1\u6570\u5668&#xff0c;\u7528\u6765\u751f\u6210\u8ba2\u5355\u53f7 1, 2, 3, &#8230;&#xff1b;<\/li>\n<li>typing.TypedDict&#xff1a;\u58f0\u660e\u300c\u5e26\u56fa\u5b9a\u5b57\u6bb5\u7684 dict \u7c7b\u578b\u300d\u3002<\/li>\n<\/ul>\n<h4>2.2.2 \u83dc\u5355\u4e0e\u53e3\u5473\u5e38\u91cf<\/h4>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">MenuItem<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    name<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    base<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    price<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">int<\/span><\/p>\n<p>MENU<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span>MenuItem<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span> <span class=\"token punctuation\">.<\/span><span class=\"token punctuation\">.<\/span><span class=\"token punctuation\">.<\/span> <span class=\"token number\">6<\/span> \u6b3e\u996e\u54c1 <span class=\"token punctuation\">.<\/span><span class=\"token punctuation\">.<\/span><span class=\"token punctuation\">.<\/span> <span class=\"token punctuation\">]<\/span><br \/>\nSUGAR <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;\u5168\u7cd6&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e03\u5206&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u534a\u7cd6&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e09\u5206&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u65e0\u7cd6&#034;<\/span><span class=\"token punctuation\">]<\/span><br \/>\nICE <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;\u6b63\u5e38\u51b0&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5c11\u51b0&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u53bb\u51b0&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u70ed\u996e&#034;<\/span><span class=\"token punctuation\">]<\/span><br \/>\nTOPPING <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;\u73cd\u73e0&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u6930\u679c&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5e03\u4e01&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u828b\u5706&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5976\u76d6&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e0d\u52a0\u6599&#034;<\/span><span class=\"token punctuation\">]<\/span><\/p>\n<p>STATUSES <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;\u5f85\u5236\u4f5c&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5236\u4f5c\u4e2d&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5df2\u5b8c\u6210&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5df2\u53d6\u9910&#034;<\/span><span class=\"token punctuation\">]<\/span><\/p>\n<ul>\n<li>MenuItem \u7528 TypedDict \u5b9a\u4e49\u4e86\u83dc\u5355\u9879\u7684\u4e09\u4e2a\u5b57\u6bb5&#xff08;\u540d\u5b57\u3001\u8336\u5e95\u3001\u4ef7\u683c&#xff09;\u3002TypedDict \u7684\u597d\u5904\u662f&#xff1a;\u5199 m[&#034;name&#034;] \u65f6 IDE \u6709\u8865\u5168\u3001\u6709\u7c7b\u578b\u68c0\u67e5&#xff1b;<\/li>\n<li>MENU \u662f 6 \u6b3e\u5976\u8336&#xff0c;\u6bcf\u6b3e\u6709\u56fa\u5b9a\u7684\u8336\u5e95\u548c\u4ef7\u683c&#xff1b;<\/li>\n<li>SUGAR \/ ICE \/ TOPPING&#xff1a;\u968f\u673a\u9009\u53e3\u5473\u7528&#xff1b;<\/li>\n<li>STATUSES&#xff1a;\u8ba2\u5355\u7684\u56db\u79cd\u72b6\u6001&#xff0c;\u524d\u7aef\u7528\u6765\u6e32\u67d3\u72b6\u6001\u8272\u5757\u3002<\/li>\n<\/ul>\n<h4>2.2.3 Order \u4e0e Snapshot \u7c7b\u578b<\/h4>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">Order<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">,<\/span> total<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u8ba2\u5355\u7ed3\u6784. total&#061;False \u56e0\u4e3a ready_since \u4ec5\u5728\u5236\u4f5c\u5b8c\u6210\u540e\u624d\u5b58\u5728.&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token builtin\">id<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">int<\/span><br \/>\n    drink<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    base<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    price<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">int<\/span><br \/>\n    sugar<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    ice<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    topping<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    status<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    progress<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">int<\/span><br \/>\n    created_at<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    ready_since<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">int<\/span><\/p>\n<ul>\n<li>total&#061;False \u662f\u5173\u952e&#xff1a;\u9ed8\u8ba4 TypedDict \u8981\u6c42\u6240\u6709\u5b57\u6bb5\u90fd\u5fc5\u987b\u5b58\u5728\u3002\u4f46\u8ba2\u5355\u91cc\u7684 ready_since&#xff08;\u5df2\u5b8c\u6210\u4e86\u51e0\u4e2a tick&#xff09;\u53ea\u5728\u8ba2\u5355\u53d8\u6210\u300c\u5df2\u5b8c\u6210\u300d\u4e4b\u540e\u624d\u51fa\u73b0&#xff0c;\u65b0\u5efa\u8ba2\u5355\u65f6\u6ca1\u6709\u3002\u6240\u4ee5\u7528 total&#061;False \u8868\u793a\u300c\u6240\u6709\u5b57\u6bb5\u90fd\u662f\u53ef\u9009\u7684\u300d&#xff1b;<\/li>\n<li>\u8fd9\u6837\u8bbe\u8ba1\u65e2\u4fdd\u7559\u4e86\u7c7b\u578b\u63d0\u793a&#xff0c;\u53c8\u5141\u8bb8\u5b57\u6bb5\u6e10\u8fdb\u5f0f\u6dfb\u52a0\u3002<\/li>\n<\/ul>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">Snapshot<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    time<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    orders<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span>Order<span class=\"token punctuation\">]<\/span><\/p>\n<ul>\n<li>Snapshot \u662f\u6bcf\u6b21\u5e7f\u64ad\u8981\u63a8\u7ed9\u524d\u7aef\u7684\u5b8c\u6574\u6570\u636e&#xff1a;\u5f53\u524d\u65f6\u95f4 &#043; \u6240\u6709\u8ba2\u5355\u5217\u8868\u3002<\/li>\n<\/ul>\n<h4>2.2.4 \u5171\u4eab\u72b6\u6001<\/h4>\n<p>order_seq <span class=\"token operator\">&#061;<\/span> count<span class=\"token punctuation\">(<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span>                       <span class=\"token comment\"># \u8ba2\u5355\u53f7\u81ea\u589e\u5668<\/span><br \/>\norders<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">dict<\/span><span class=\"token punctuation\">[<\/span><span class=\"token builtin\">int<\/span><span class=\"token punctuation\">,<\/span> Order<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">}<\/span>              <span class=\"token comment\"># order_id -&gt; order \u8be6\u60c5<\/span><\/p>\n<ul>\n<li>order_seq &#061; count(1)&#xff1a;count(1) \u8fd4\u56de\u4e00\u4e2a\u751f\u6210\u5668&#xff0c;\u6bcf\u6b21 next(order_seq) \u5f97\u5230 1, 2, 3, \u2026\u3002\u6bd4\u624b\u52a8\u7ef4\u62a4 id &#043;&#061; 1 \u66f4\u4f18\u96c5&#xff0c;\u7ebf\u7a0b\u5b89\u5168&#xff08;\u867d\u7136\u672c\u9879\u76ee\u5355\u7ebf\u7a0b&#xff09;&#xff1b;<\/li>\n<li>orders&#xff1a;\u6240\u6709\u8ba2\u5355\u7684\u5b57\u5178&#xff0c;key \u662f\u8ba2\u5355\u53f7&#xff0c;value \u662f Order\u3002\u8fd9\u662f\u6574\u4e2a\u5e94\u7528\u7684\u300c\u5185\u5b58\u6570\u636e\u5e93\u300d\u3002<\/li>\n<\/ul>\n<p>\u8fd9\u4e24\u4e2a\u662f\u6a21\u5757\u7ea7\u53d8\u91cf&#xff0c;\u6574\u4e2a\u8fdb\u7a0b\u5171\u4eab\u3002\u6240\u6709 advance()\u3001new_order()\u3001snapshot() \u90fd\u5728\u64cd\u4f5c\u5b83\u4eec\u3002\u8fd9\u4e5f\u662f\u4e3a\u4ec0\u4e48\u6570\u636e\u5c42\u8981\u548c\u4f20\u8f93\u5c42\u89e3\u8026\u2014\u2014\u72b6\u6001\u96c6\u4e2d\u7ba1\u7406&#xff0c;\u8c01\u8981\u7528\u8c01\u62ff\u3002<\/p>\n<h4>2.2.5 \u65f6\u95f4\u6233\u51fd\u6570<\/h4>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">now_iso<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;ISO8601 \u65f6\u95f4\u6233 (Python 3.14 \u63a8\u8350\u7528 UTC \u522b\u540d, \u907f\u514d\u5e9f\u5f03\u7684 utcnow()).&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token keyword\">return<\/span> datetime<span class=\"token punctuation\">.<\/span>now<span class=\"token punctuation\">(<\/span>UTC<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>isoformat<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u8fd4\u56de\u5f62\u5982 &#034;2026-08-04T12:34:56.789&#043;00:00&#034; \u7684\u5b57\u7b26\u4e32&#xff1b;<\/li>\n<li>\u524d\u7aef\u7528 new Date(iso) \u89e3\u6790\u540e\u53d6\u65f6\u5206\u79d2\u663e\u793a\u5728\u65f6\u949f\u4e0a&#xff1b;<\/li>\n<li>\u7528 UTC \u800c\u975e utcnow()&#xff1a;\u524d\u8005\u8fd4\u56de\u5e26\u65f6\u533a\u7684 datetime&#xff0c;\u540e\u8005\u8fd4\u56de\u65e0\u65f6\u533a\u7684&#xff08;\u5df2\u5e9f\u5f03&#xff09;\u3002<\/li>\n<\/ul>\n<h4>2.2.6 \u751f\u6210\u65b0\u8ba2\u5355<\/h4>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">new_order<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> Order<span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u968f\u673a\u751f\u6210\u4e00\u4efd\u65b0\u8ba2\u5355.&#034;&#034;&#034;<\/span><br \/>\n    m <span class=\"token operator\">&#061;<\/span> random<span class=\"token punctuation\">.<\/span>choice<span class=\"token punctuation\">(<\/span>MENU<span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">return<\/span> Order<span class=\"token punctuation\">(<\/span><br \/>\n        <span class=\"token builtin\">id<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token builtin\">next<\/span><span class=\"token punctuation\">(<\/span>order_seq<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        drink<span class=\"token operator\">&#061;<\/span>m<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        base<span class=\"token operator\">&#061;<\/span>m<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;base&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        price<span class=\"token operator\">&#061;<\/span>m<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;price&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        sugar<span class=\"token operator\">&#061;<\/span>random<span class=\"token punctuation\">.<\/span>choice<span class=\"token punctuation\">(<\/span>SUGAR<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        ice<span class=\"token operator\">&#061;<\/span>random<span class=\"token punctuation\">.<\/span>choice<span class=\"token punctuation\">(<\/span>ICE<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        topping<span class=\"token operator\">&#061;<\/span>random<span class=\"token punctuation\">.<\/span>choice<span class=\"token punctuation\">(<\/span>TOPPING<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        status<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;\u5f85\u5236\u4f5c&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        progress<span class=\"token operator\">&#061;<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        created_at<span class=\"token operator\">&#061;<\/span>now_iso<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    <span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u968f\u673a\u9009\u4e00\u6b3e\u83dc\u5355\u3001\u968f\u673a\u9009\u7cd6\u5ea6\/\u51b0\u5ea6\/\u52a0\u6599&#xff1b;<\/li>\n<li>id \u7528 next(order_seq) \u81ea\u589e&#xff1b;<\/li>\n<li>\u65b0\u8ba2\u5355\u521d\u59cb\u72b6\u6001 &#034;\u5f85\u5236\u4f5c&#034;\u3001\u8fdb\u5ea6 0&#xff1b;<\/li>\n<li>Order(&#8230;) \u770b\u8d77\u6765\u50cf\u6784\u9020\u51fd\u6570&#xff0c;\u5176\u5b9e TypedDict \u53ea\u662f\u7c7b\u578b\u63d0\u793a&#xff0c;\u8fd0\u884c\u65f6\u5b83\u5c31\u662f\u666e\u901a dict&#xff0c;Order(&#8230;) \u7b49\u4ef7\u4e8e {&#034;id&#034;: &#8230;, &#034;drink&#034;: &#8230;, &#8230;}\u3002<\/li>\n<\/ul>\n<h4>2.2.7 \u6838\u5fc3&#xff1a;advance() \u63a8\u8fdb\u903b\u8f91<\/h4>\n<p>\u8fd9\u662f\u6570\u636e\u5c42\u6700\u590d\u6742\u7684\u51fd\u6570&#xff0c;\u9010\u6bb5\u62c6&#xff1a;<\/p>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">advance<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> Snapshot<span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u63a8\u8fdb\u6240\u6709\u672a\u5b8c\u6210\u8ba2\u5355, \u8fd4\u56de\u6700\u65b0\u5feb\u7167 (\u6309 id \u5012\u5e8f).&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token comment\"># 1) \u5076\u5c14(20% \u6982\u7387)\u751f\u6210\u65b0\u8ba2\u5355<\/span><br \/>\n    <span class=\"token keyword\">if<\/span> random<span class=\"token punctuation\">.<\/span>random<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&lt;<\/span> <span class=\"token number\">0.2<\/span> <span class=\"token keyword\">or<\/span> <span class=\"token keyword\">not<\/span> orders<span class=\"token punctuation\">:<\/span><br \/>\n        o <span class=\"token operator\">&#061;<\/span> new_order<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        orders<span class=\"token punctuation\">[<\/span>o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;id&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> o<\/p>\n<ul>\n<li>random.random() \u8fd4\u56de [0, 1) \u7684\u6d6e\u70b9\u6570&#xff0c;\u5c0f\u4e8e 0.2 \u7684\u6982\u7387\u7ea6 20%&#xff1b;<\/li>\n<li>or not orders&#xff1a;\u5982\u679c\u5f53\u524d\u4e00\u4e2a\u8ba2\u5355\u90fd\u6ca1\u6709&#xff08;\u521a\u542f\u52a8&#xff09;&#xff0c;\u5f3a\u5236\u751f\u6210\u4e00\u4e2a&#xff0c;\u907f\u514d\u770b\u677f\u7a7a\u767d&#xff1b;<\/li>\n<li>\u751f\u6210\u540e\u5b58\u8fdb orders \u5b57\u5178\u3002<\/li>\n<\/ul>\n<p>    <span class=\"token comment\"># 2) \u63a8\u8fdb\u8fdb\u5ea6<\/span><br \/>\n    completed<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span><span class=\"token builtin\">int<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\n    <span class=\"token keyword\">for<\/span> oid<span class=\"token punctuation\">,<\/span> o <span class=\"token keyword\">in<\/span> orders<span class=\"token punctuation\">.<\/span>items<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u53d6\u9910&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">continue<\/span>                                <span class=\"token comment\"># \u5df2\u53d6\u9910\u7684\u4e0d\u518d\u63a8\u8fdb<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;\u5f85\u5236\u4f5c&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u5236\u4f5c\u4e2d&#034;<\/span>                    <span class=\"token comment\"># \u5f85\u5236\u4f5c \u2192 \u5236\u4f5c\u4e2d&#xff08;\u4e00\u6b21\u6027&#xff09;<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;\u5236\u4f5c\u4e2d&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;progress&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">min<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">100<\/span><span class=\"token punctuation\">,<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;progress&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#043;<\/span> random<span class=\"token punctuation\">.<\/span>randint<span class=\"token punctuation\">(<\/span><span class=\"token number\">8<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">18<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;progress&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&gt;&#061;<\/span> <span class=\"token number\">100<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u5b8c\u6210&#034;<\/span><br \/>\n        <span class=\"token comment\"># \u5df2\u5b8c\u6210 3 \u4e2a tick \u540e\u81ea\u52a8\u51fa\u961f<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u5b8c\u6210&#034;<\/span> <span class=\"token keyword\">and<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;progress&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&gt;&#061;<\/span> <span class=\"token number\">100<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;ready_since&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> o<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;ready_since&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#043;<\/span> <span class=\"token number\">1<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;ready_since&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&gt;&#061;<\/span> <span class=\"token number\">3<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                completed<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span>oid<span class=\"token punctuation\">)<\/span><\/p>\n<p>\u72b6\u6001\u673a&#xff1a;<\/p>\n<p>\u5f85\u5236\u4f5c \u2500\u2500(\u9996\u6b21advance)\u2500\u2500&gt; \u5236\u4f5c\u4e2d \u2500\u2500(progress\u6bcftick &#043;8~18)\u2500\u2500&gt; \u5df2\u5b8c\u6210 \u2500\u2500(\u518d3 tick)\u2500\u2500&gt; \u5df2\u53d6\u9910<\/p>\n<ul>\n<li>\u5f85\u5236\u4f5c \u2192 \u5236\u4f5c\u4e2d&#xff1a;\u8fdb\u5165 advance \u7684\u7b2c\u4e00\u4e2a tick \u5c31\u8f6c&#xff0c;\u53ea\u8f6c\u4e00\u6b21&#xff1b;<\/li>\n<li>\u5236\u4f5c\u4e2d&#xff1a;\u6bcf tick \u8fdb\u5ea6\u968f\u673a\u52a0 8~18&#xff0c;\u5c01\u9876 100\u3002\u5230 100 \u5c31 \u5df2\u5b8c\u6210&#xff1b;<\/li>\n<li>\u5df2\u5b8c\u6210&#xff1a;\u7528\u4e00\u4e2a ready_since \u8ba1\u6570\u5668&#xff0c;\u8bb0\u5f55\u5df2\u5b8c\u6210\u51e0\u4e2a tick\u3002\u6ee1 3 \u4e2a tick \u540e\u6807\u8bb0\u4e3a\u300c\u5df2\u53d6\u9910\u300d&#xff08;\u653e\u8fdb completed \u5217\u8868&#xff0c;\u5faa\u73af\u5916\u7edf\u4e00\u5904\u7406&#xff09;&#xff1b;<\/li>\n<li>o.get(&#034;ready_since&#034;, 0)&#xff1a;\u56e0\u4e3a ready_since \u662f\u6e10\u8fdb\u5b57\u6bb5&#xff08;\u65b0\u5efa\u65f6\u6ca1\u6709&#xff09;&#xff0c;\u7528 .get \u5e26\u9ed8\u8ba4\u503c&#xff0c;\u907f\u514d KeyError\u3002<\/li>\n<\/ul>\n<p>    <span class=\"token keyword\">for<\/span> oid <span class=\"token keyword\">in<\/span> completed<span class=\"token punctuation\">:<\/span><br \/>\n        orders<span class=\"token punctuation\">[<\/span>oid<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u53d6\u9910&#034;<\/span><\/p>\n<p>    <span class=\"token comment\"># 3) \u961f\u5217\u6700\u591a\u4fdd\u7559 8 \u6761\u5df2\u53d6\u9910<\/span><br \/>\n    finished <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span>oid <span class=\"token keyword\">for<\/span> oid<span class=\"token punctuation\">,<\/span> o <span class=\"token keyword\">in<\/span> orders<span class=\"token punctuation\">.<\/span>items<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">if<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u53d6\u9910&#034;<\/span><span class=\"token punctuation\">]<\/span><br \/>\n    <span class=\"token keyword\">for<\/span> oid <span class=\"token keyword\">in<\/span> finished<span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">:<\/span><span class=\"token operator\">&#8211;<\/span><span class=\"token number\">8<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token keyword\">if<\/span> <span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>finished<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&gt;<\/span> <span class=\"token number\">8<\/span> <span class=\"token keyword\">else<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        orders<span class=\"token punctuation\">.<\/span>pop<span class=\"token punctuation\">(<\/span>oid<span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">None<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u5148\u628a completed \u5217\u8868\u91cc\u7684\u8ba2\u5355\u6b63\u5f0f\u6539\u6210\u300c\u5df2\u53d6\u9910\u300d&#xff1b;<\/li>\n<li>\u7136\u540e\u505a\u6e05\u7406&#xff1a;\u5df2\u53d6\u9910\u7684\u8ba2\u5355\u5982\u679c\u8d85\u8fc7 8 \u6761&#xff0c;\u628a\u6700\u8001\u7684\u51e0\u6761\u4ece\u5b57\u5178\u91cc\u5220\u6389&#xff0c;\u9632\u6b62\u5185\u5b58\u65e0\u9650\u589e\u957f&#xff1b;<\/li>\n<li>finished[:-8]&#xff1a;\u5207\u7247&#xff0c;\u4fdd\u7559\u6700\u540e 8 \u6761&#xff08;\u6700\u65b0\u7684&#xff09;&#xff0c;\u524d\u9762\u7684\u5168\u90e8 pop \u6389&#xff1b;<\/li>\n<li>if len(finished) &gt; 8 else []&#xff1a;\u4e0d\u8db3 8 \u6761\u65f6\u5207\u7247\u7ed3\u679c\u662f\u5168\u90e8&#xff0c;\u4f1a\u8bef\u5220&#xff0c;\u6240\u4ee5\u52a0\u8fd9\u4e2a\u5224\u65ad&#xff1b;<\/li>\n<li>orders.pop(oid, None)&#xff1a;\u5220\u9664 key&#xff0c;\u4e0d\u5b58\u5728\u4e5f\u4e0d\u62a5\u9519\u3002<\/li>\n<\/ul>\n<p>    <span class=\"token keyword\">return<\/span> Snapshot<span class=\"token punctuation\">(<\/span>time<span class=\"token operator\">&#061;<\/span>now_iso<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> orders<span class=\"token operator\">&#061;<\/span><span class=\"token builtin\">sorted<\/span><span class=\"token punctuation\">(<\/span>orders<span class=\"token punctuation\">.<\/span>values<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> key<span class=\"token operator\">&#061;<\/span><span class=\"token keyword\">lambda<\/span> o<span class=\"token punctuation\">:<\/span> <span class=\"token operator\">&#8211;<\/span>o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;id&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u8fd4\u56de\u5f53\u524d\u5feb\u7167&#xff1a;\u65f6\u95f4 &#043; \u6240\u6709\u8ba2\u5355&#xff08;\u6309 id \u5012\u5e8f&#xff0c;\u6700\u65b0\u7684\u5728\u6700\u524d\u9762&#xff0c;\u65b9\u4fbf\u524d\u7aef\u5c55\u793a&#xff09;&#xff1b;<\/li>\n<li>key&#061;lambda o: -o[&#034;id&#034;]&#xff1a;\u7528\u8d1f\u53f7\u5b9e\u73b0\u5012\u5e8f&#xff0c;\u7b49\u4ef7\u4e8e reverse&#061;True\u3002<\/li>\n<\/ul>\n<h4>2.2.8 snapshot() \u2014\u2014 \u4e0d\u6539\u53d8\u72b6\u6001\u7684\u67e5\u8be2<\/h4>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">snapshot<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> Snapshot<span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u8fd4\u56de\u5f53\u524d\u5feb\u7167, \u4e0d\u6539\u53d8\u72b6\u6001.&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token keyword\">return<\/span> Snapshot<span class=\"token punctuation\">(<\/span>time<span class=\"token operator\">&#061;<\/span>now_iso<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> orders<span class=\"token operator\">&#061;<\/span><span class=\"token builtin\">sorted<\/span><span class=\"token punctuation\">(<\/span>orders<span class=\"token punctuation\">.<\/span>values<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> key<span class=\"token operator\">&#061;<\/span><span class=\"token keyword\">lambda<\/span> o<span class=\"token punctuation\">:<\/span> <span class=\"token operator\">&#8211;<\/span>o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;id&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u548c advance() \u7684\u8fd4\u56de\u503c\u4e00\u6837&#xff0c;\u4f46\u4e0d\u63a8\u8fdb\u8fdb\u5ea6\u3001\u4e0d\u751f\u6210\u8ba2\u5355&#xff1b;<\/li>\n<li>\u7ed9 WebSocket \u7684 snapshot \u547d\u4ee4\u7528\u2014\u2014\u524d\u7aef\u60f3\u968f\u65f6\u62c9\u4e00\u6b21\u5f53\u524d\u72b6\u6001&#xff0c;\u4e0d\u5e94\u8be5\u6539\u53d8\u5b83\u3002<\/li>\n<\/ul>\n<hr \/>\n<h3>2.3 \u72b6\u6001\u673a\u4e00\u89c8<\/h3>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/08\/20260804081742-6a71a02619090.jpg\" alt=\"\u8ba2\u5355\u5904\u7406\u6d41\u7a0b\u56fe\" \/><\/p>\n<ul>\n<li>\u6bcf\u6b21\u8c03\u7528 advance() &#061; \u4e00\u4e2a tick &#061; 0.8 \u79d2&#xff08;\u7531\u7b2c 5 \u7ae0\u5e7f\u64ad\u5668\u63a7\u5236&#xff09;&#xff1b;<\/li>\n<li>\u4e00\u4e2a\u8ba2\u5355\u4ece\u751f\u6210\u5230\u300c\u5df2\u53d6\u9910\u300d\u5927\u7ea6\u9700\u8981&#xff1a;1&#xff08;\u8f6c\u5236\u4f5c\u4e2d&#xff09;&#043; ~7&#xff08;\u8fdb\u5ea6\u5230100&#xff09;&#043; 3&#xff08;\u7b49\u53d6\u9910&#xff09;\u2248 11 \u4e2a tick \u2248 9 \u79d2\u3002<\/li>\n<\/ul>\n<h3>2.4 \u4e3a\u4ec0\u4e48\u8fd9\u4e00\u7ae0\u6ca1\u6709\u300c\u8fd0\u884c\u9a8c\u8bc1\u300d&#xff1f;<\/h3>\n<p>\u6570\u636e\u5c42\u6ca1\u6709\u5165\u53e3\u51fd\u6570&#xff0c;\u5355\u72ec\u8dd1\u770b\u4e0d\u5230\u6548\u679c\u3002\u4f46\u5b83\u4f1a\u5728\u540e\u7eed\u7ae0\u8282\u88ab broadcaster.py&#xff08;\u6bcf 0.8s \u8c03 advance()&#xff09;\u548c ws.py&#xff08;\u54cd\u5e94 add\/snapshot\/pickup \u547d\u4ee4&#xff09;\u4f7f\u7528\u3002<\/p>\n<p>\u5982\u679c\u4f60\u60f3\u73b0\u5728\u5c31\u9a8c\u8bc1\u5b83\u903b\u8f91\u5bf9\u4e0d\u5bf9&#xff0c;\u53ef\u4ee5\u4e34\u65f6\u5199\u4e2a\u6d4b\u8bd5&#xff1a;<\/p>\n<p>uv run python <span class=\"token parameter variable\">-c<\/span> <span class=\"token string\">&#034;<br \/>\nfrom src.models import advance, orders<br \/>\nimport time<br \/>\nfor _ in range(15):<br \/>\n    snap &#061; advance()<br \/>\n    print(f&#039;\u5171 {len(snap[<span class=\"token entity\" title=\"\\\\&quot;\">\\\\&#034;<\/span>orders<span class=\"token entity\" title=\"\\\\&quot;\">\\\\&#034;<\/span>])} \u5355:&#039;, [(o[&#039;id&#039;], o[&#039;status&#039;], o[&#039;progress&#039;]) for o in snap[&#039;orders&#039;][:3]])<br \/>\n    time.sleep(0.3)<br \/>\n&#034;<\/span><\/p>\n<p>\u4f60\u4f1a\u770b\u5230\u8ba2\u5355\u4ece\u300c\u5f85\u5236\u4f5c\u300d\u9010\u6e10\u63a8\u8fdb\u5230\u300c\u5df2\u53d6\u9910\u300d&#xff0c;\u8001\u7684\u5df2\u53d6\u9910\u8ba2\u5355\u4f1a\u6d88\u5931\u3002<\/p>\n<hr \/>\n<p>\u4e0b\u4e00\u7ae0 \u2192 03-SSE\u6a21\u5757-sse.md&#xff1a;\u7528 StreamingResponse \u5b9e\u73b0 SSE \u5355\u5411\u63a8\u9001\u3002<\/p>\n<hr \/>\n<h2>\u7b2c 3 \u7ae0 \u00b7 SSE \u6a21\u5757 sse.py<\/h2>\n<h3>\u672c\u7ae0\u76ee\u6807<\/h3>\n<p>\u5b9e\u73b0\u9879\u76ee\u7b2c\u4e00\u4e2a\u4f20\u8f93\u6a21\u5757\u2014\u2014SSE&#xff08;Server-Sent Events&#xff0c;\u670d\u52a1\u5668\u5355\u5411\u63a8\u9001&#xff09;\u3002\u5b66\u5b8c\u672c\u7ae0\u4f60\u5c06\u7406\u89e3&#xff1a;<\/p>\n<ul>\n<li>SSE \u662f\u4ec0\u4e48\u3001\u4e3a\u4ec0\u4e48\u5b83\u300c\u591f\u7528\u53c8\u7b80\u5355\u300d&#xff1b;<\/li>\n<li>\u7528 FastAPI \u7684 StreamingResponse \u600e\u4e48\u5b9e\u73b0\u4e00\u4e2a SSE \u7aef\u70b9&#xff1b;<\/li>\n<li>\u6bcf\u4e2a\u8fde\u63a5\u72ec\u4eab\u4e00\u4e2a asyncio.Queue&#xff0c;\u5e7f\u64ad\u5668\u53ea\u8d1f\u8d23\u5f80 Queue \u91cc\u585e\u4e8b\u4ef6&#xff0c;\u53d1\u9001\u4e0d\u963b\u585e&#xff1b;<\/li>\n<li>SSE \u5e27\u7684\u6587\u672c\u683c\u5f0f&#xff08;event: \/ data: \/ \u7a7a\u884c&#xff09;&#xff1b;<\/li>\n<li>\u4e09\u4e2a\u5173\u952e\u54cd\u5e94\u5934\u7684\u4f5c\u7528\u3002<\/li>\n<\/ul>\n<hr \/>\n<h3>3.1 \u5148\u7406\u89e3 SSE \u662f\u4ec0\u4e48<\/h3>\n<p>SSE&#xff08;Server-Sent Events&#xff09;\u662f HTML5 \u6807\u51c6\u91cc\u57fa\u4e8e HTTP \u7684\u670d\u52a1\u5668\u63a8\u9001\u6280\u672f&#xff1a;<\/p>\n<ul>\n<li>\n<p>\u670d\u52a1\u5668\u54cd\u5e94\u5934 Content-Type: text\/event-stream&#xff0c;\u544a\u8bc9\u6d4f\u89c8\u5668\u300c\u8fd9\u662f\u4e00\u6761\u4e8b\u4ef6\u6d41\u300d&#xff1b;<\/p>\n<\/li>\n<li>\n<p>\u6d4f\u89c8\u5668\u7528 new EventSource(url) \u5efa\u7acb\u8fde\u63a5&#xff0c;\u81ea\u52a8\u91cd\u8fde&#xff08;\u65ad\u4e86\u6d4f\u89c8\u5668\u4f1a\u81ea\u52a8\u91cd\u8fde&#xff09;&#xff1b;<\/p>\n<\/li>\n<li>\n<p>\u670d\u52a1\u5668\u628a\u6570\u636e\u6309\u8fd9\u4e2a\u683c\u5f0f\u4e00\u6bb5\u6bb5\u53d1&#xff1a;<\/p>\n<p> event: \u4e8b\u4ef6\u540d<br \/>\ndata: \u6570\u636e(\u4e00\u884c\u6216\u591a\u884c)<\/p>\n<p>\u6bcf\u6bb5\u4e4b\u95f4\u7528\u7a7a\u884c\u5206\u9694\u3002\u6d4f\u89c8\u5668\u6536\u5230\u540e\u89e6\u53d1 es.addEventListener(&#034;\u4e8b\u4ef6\u540d&#034;, &#8230;)\u3002<\/p>\n<\/li>\n<li>\n<p>\u5355\u5411&#xff1a;\u670d\u52a1\u5668 \u2192 \u6d4f\u89c8\u5668\u3002\u6d4f\u89c8\u5668\u4e0d\u80fd\u901a\u8fc7\u540c\u4e00\u6761\u8fde\u63a5\u53d1\u6570\u636e\u56de\u53bb\u3002<\/p>\n<\/li>\n<\/ul>\n<p>\u9002\u5408&#xff1a;\u80a1\u7968\u884c\u60c5\u3001\u901a\u77e5\u3001\u65e5\u5fd7\u6d41\u3001\u6211\u4eec\u7684\u300c\u8ba2\u5355\u770b\u677f\u300d\u2014\u2014\u670d\u52a1\u5668\u63a8\u3001\u6d4f\u89c8\u5668\u53ea\u770b\u3002<\/p>\n<h3>3.2 \u539f\u59cb\u5b8c\u6574\u4ee3\u7801<\/h3>\n<p>\u65b0\u5efa\u6587\u4ef6 src\/sse.py&#xff0c;\u5b8c\u6574\u7167\u6284&#xff1a;<\/p>\n<p><span class=\"token triple-quoted-string string\">&#034;&#034;&#034;<br \/>\n\u6559\u5b66\u6a21\u5757 1: SSE \u5355\u5411\u63a8\u9001.<\/p>\n<p>\u5173\u952e\u70b9<br \/>\n&#8212;&#8212;<br \/>\n&#8211; \u6bcf\u4e2a\u8fde\u63a5\u72ec\u5360\u4e00\u4e2a asyncio.Queue, \u540e\u53f0\u5e7f\u64ad\u4efb\u52a1\u628a\u4e8b\u4ef6\u585e\u8fdb\u6bcf\u4e2a Queue<br \/>\n&#8211; StreamingResponse \u7684 media_type&#061;&#039;text\/event-stream&#039; \u544a\u8bc9\u6d4f\u89c8\u5668\u8fd9\u662f SSE<br \/>\n&#8211; \u5173\u95ed\u8fde\u63a5\u65f6 (Generator Exit \/ \u5f02\u5e38) \u81ea\u52a8\u4ece\u8ba2\u9605\u96c6\u5408\u79fb\u9664, \u9632\u6b62\u5185\u5b58\u6cc4\u6f0f<br \/>\n&#8211; \u4e09\u6761\u5173\u952e\u54cd\u5e94\u5934:<br \/>\n    Cache-Control: no-cache        \u4e0d\u7f13\u5b58<br \/>\n    Connection: keep-alive         \u4fdd\u6301\u957f\u8fde\u63a5<br \/>\n    X-Accel-Buffering: no          \u5173\u95ed nginx \u7f13\u51b2, \u5b9e\u65f6\u63a8\u9001<br \/>\n&#034;&#034;&#034;<\/span><\/p>\n<p><span class=\"token keyword\">import<\/span> asyncio<br \/>\n<span class=\"token keyword\">import<\/span> json<br \/>\n<span class=\"token keyword\">from<\/span> typing <span class=\"token keyword\">import<\/span> TypedDict<\/p>\n<p><span class=\"token keyword\">from<\/span> fastapi <span class=\"token keyword\">import<\/span> APIRouter<br \/>\n<span class=\"token keyword\">from<\/span> fastapi<span class=\"token punctuation\">.<\/span>responses <span class=\"token keyword\">import<\/span> StreamingResponse<\/p>\n<p><span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>models <span class=\"token keyword\">import<\/span> MENU<span class=\"token punctuation\">,<\/span> STATUSES<\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">_QueueItem<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;broadcaster \u63a8\u5165 Queue \u7684\u4e8b\u4ef6\u9879.&#034;&#034;&#034;<\/span><br \/>\n    event<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    data<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><\/p>\n<p>router <span class=\"token operator\">&#061;<\/span> APIRouter<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token comment\"># \u6240\u6709 SSE \u5ba2\u6237\u7aef\u7684 Queue \u96c6\u5408 (\u7531 broadcaster \u5199\u5165)<\/span><br \/>\nsse_clients<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">set<\/span><span class=\"token punctuation\">[<\/span>asyncio<span class=\"token punctuation\">.<\/span>Queue<span class=\"token punctuation\">[<\/span>_QueueItem<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">set<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token decorator annotation punctuation\">&#064;router<span class=\"token punctuation\">.<\/span>get<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\/sse\/orders&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n<span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">sse_orders<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> StreamingResponse<span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u5efa\u7acb SSE \u8fde\u63a5, \u6301\u7eed\u63a5\u6536 orders \u4e8b\u4ef6.&#034;&#034;&#034;<\/span><br \/>\n    queue<span class=\"token punctuation\">:<\/span> asyncio<span class=\"token punctuation\">.<\/span>Queue<span class=\"token punctuation\">[<\/span>_QueueItem<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> asyncio<span class=\"token punctuation\">.<\/span>Queue<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    sse_clients<span class=\"token punctuation\">.<\/span>add<span class=\"token punctuation\">(<\/span>queue<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">event_stream<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token comment\"># \u9996\u6b21\u53d1 hello, \u8ba9\u524d\u7aef\u7acb\u5373\u611f\u77e5\u8fde\u63a5\u6210\u529f\u5e76\u62ff\u5230\u83dc\u5355<\/span><br \/>\n            hello <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;menu&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">[<\/span>m<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token keyword\">for<\/span> m <span class=\"token keyword\">in<\/span> MENU<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;statuses&#034;<\/span><span class=\"token punctuation\">:<\/span> STATUSES<span class=\"token punctuation\">}<\/span><br \/>\n            <span class=\"token keyword\">yield<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;event: hello\\\\ndata: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>json<span class=\"token punctuation\">.<\/span>dumps<span class=\"token punctuation\">(<\/span>hello<span class=\"token punctuation\">,<\/span> ensure_ascii<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">\\\\n\\\\n&#034;<\/span><\/span><\/p>\n<p>            <span class=\"token comment\"># \u4e3b\u5faa\u73af: \u4ece Queue \u53d6\u4e8b\u4ef6\u5e76\u4ee5 SSE \u5e27\u683c\u5f0f\u5199\u51fa<\/span><br \/>\n            <span class=\"token keyword\">while<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                item <span class=\"token operator\">&#061;<\/span> <span class=\"token keyword\">await<\/span> queue<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">yield<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;event: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>item<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#039;event&#039;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">\\\\ndata: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>item<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#039;data&#039;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">\\\\n\\\\n&#034;<\/span><\/span><br \/>\n        <span class=\"token keyword\">finally<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token comment\"># \u5ba2\u6237\u7aef\u65ad\u5f00 \/ \u5f02\u5e38 -&gt; \u9000\u8ba2, \u907f\u514d\u6cc4\u6f0f<\/span><br \/>\n            sse_clients<span class=\"token punctuation\">.<\/span>discard<span class=\"token punctuation\">(<\/span>queue<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">return<\/span> StreamingResponse<span class=\"token punctuation\">(<\/span><br \/>\n        event_stream<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        media_type<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;text\/event-stream&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        headers<span class=\"token operator\">&#061;<\/span><span class=\"token punctuation\">{<\/span><br \/>\n            <span class=\"token string\">&#034;Cache-Control&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;no-cache&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string\">&#034;Connection&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;keep-alive&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string\">&#034;X-Accel-Buffering&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;no&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    <span class=\"token punctuation\">)<\/span><\/p>\n<hr \/>\n<h3>3.3 \u9010\u6bb5\u8bb2\u89e3<\/h3>\n<h4>3.3.1 \u5bfc\u5165<\/h4>\n<p><span class=\"token keyword\">import<\/span> asyncio<br \/>\n<span class=\"token keyword\">import<\/span> json<br \/>\n<span class=\"token keyword\">from<\/span> typing <span class=\"token keyword\">import<\/span> TypedDict<\/p>\n<p><span class=\"token keyword\">from<\/span> fastapi <span class=\"token keyword\">import<\/span> APIRouter<br \/>\n<span class=\"token keyword\">from<\/span> fastapi<span class=\"token punctuation\">.<\/span>responses <span class=\"token keyword\">import<\/span> StreamingResponse<\/p>\n<p><span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>models <span class=\"token keyword\">import<\/span> MENU<span class=\"token punctuation\">,<\/span> STATUSES<\/p>\n<ul>\n<li>asyncio&#xff1a;\u7528 asyncio.Queue \u7ed9\u6bcf\u4e2a\u8fde\u63a5\u5f53\u300c\u4fe1\u7bb1\u300d&#xff1b;<\/li>\n<li>json&#xff1a;\u5e8f\u5217\u5316 hello \u6d88\u606f&#xff1b;<\/li>\n<li>APIRouter&#xff1a;FastAPI \u7684\u8def\u7531\u5206\u7ec4\u5de5\u5177&#xff0c;\u628a \/sse\/orders \u5355\u72ec\u88c5\u8fdb sse.router&#xff0c;\u7b2c 6 \u7ae0\u5728 app.py \u91cc include_router \u6302\u4e0a\u53bb&#xff1b;<\/li>\n<li>StreamingResponse&#xff1a;FastAPI \u7684\u6d41\u5f0f\u54cd\u5e94\u7c7b&#xff0c;\u63a5\u6536\u4e00\u4e2a\u5f02\u6b65\u751f\u6210\u5668&#xff0c;\u751f\u6210\u5668 yield \u4ec0\u4e48\u5c31\u5f80\u5ba2\u6237\u7aef\u53d1\u4ec0\u4e48&#xff1b;<\/li>\n<li>from .models import MENU, STATUSES&#xff1a;\u76f8\u5bf9\u5bfc\u5165&#xff0c;\u62ff\u83dc\u5355\u548c\u72b6\u6001\u5217\u8868&#xff0c;\u63e1\u624b\u65f6\u53d1\u7ed9\u524d\u7aef\u3002\u6ce8\u610f . \u8868\u793a\u300c\u540c\u5305&#xff08;src&#xff09;\u5185\u300d\u3002<\/li>\n<\/ul>\n<h4>3.3.2 Queue \u4e8b\u4ef6\u9879\u7684\u7c7b\u578b<\/h4>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">_QueueItem<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;broadcaster \u63a8\u5165 Queue \u7684\u4e8b\u4ef6\u9879.&#034;&#034;&#034;<\/span><br \/>\n    event<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    data<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><\/p>\n<ul>\n<li>\u5e7f\u64ad\u5668&#xff08;\u7b2c 5 \u7ae0&#xff09;\u5f80\u6bcf\u4e2a Queue \u63a8\u7684\u662f {&#034;event&#034;: &#034;orders&#034;, &#034;data&#034;: &#034;&#8230;json\u5b57\u7b26\u4e32&#8230;&#034;}&#xff1b;<\/li>\n<li>\u7528 TypedDict \u7ed9\u4e2a\u7c7b\u578b\u540d&#xff0c;\u4e0b\u9762 sse_clients \u7684\u7c7b\u578b\u6807\u6ce8\u66f4\u6e05\u6670&#xff1b;<\/li>\n<li>\u540d\u5b57\u5e26\u4e0b\u5212\u7ebf _QueueItem&#xff1a;\u7ea6\u5b9a\u4fd7\u6210\u8868\u793a\u300c\u6a21\u5757\u5185\u90e8\u7528\u300d\u3002<\/li>\n<\/ul>\n<h4>3.3.3 \u8def\u7531\u5bf9\u8c61 &#043; \u5ba2\u6237\u7aef\u96c6\u5408<\/h4>\n<p>router <span class=\"token operator\">&#061;<\/span> APIRouter<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token comment\"># \u6240\u6709 SSE \u5ba2\u6237\u7aef\u7684 Queue \u96c6\u5408 (\u7531 broadcaster \u5199\u5165)<\/span><br \/>\nsse_clients<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">set<\/span><span class=\"token punctuation\">[<\/span>asyncio<span class=\"token punctuation\">.<\/span>Queue<span class=\"token punctuation\">[<\/span>_QueueItem<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">set<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>router &#061; APIRouter()&#xff1a;\u521b\u5efa\u4e00\u4e2a\u72ec\u7acb\u8def\u7531\u7ec4&#xff0c;\u672c\u6a21\u5757\u6240\u6709\u8def\u7531\u90fd\u6302\u5728\u5b83\u4e0a\u9762&#xff1b;<\/li>\n<li>sse_clients&#xff1a;\u6240\u6709\u5f53\u524d SSE \u8fde\u63a5\u7684 Queue \u96c6\u5408\u3002\u8fd9\u662f\u4e00\u4e2a\u6a21\u5757\u7ea7\u5168\u5c40\u53d8\u91cf&#xff0c;\u4f1a\u88ab\u7b2c 5 \u7ae0\u7684 broadcaster.py \u5bfc\u5165\u5e76\u5f80\u91cc\u585e\u4e8b\u4ef6&#xff1b;<\/li>\n<li>\u4e3a\u4ec0\u4e48\u5b58\u7684\u662f Queue \u800c\u4e0d\u662f\u8fde\u63a5\u5bf9\u8c61&#xff1f;\u56e0\u4e3a SSE \u7684 StreamingResponse \u6ca1\u6709\u73b0\u6210\u7684\u300c\u53d1\u9001\u65b9\u6cd5\u300d&#xff0c;\u6211\u4eec\u7528\u4e00\u4e2a Queue \u5f53\u7f13\u51b2&#xff1a;\u5e7f\u64ad\u5668 queue.put(&#8230;)&#xff0c;\u8fde\u63a5\u534f\u7a0b queue.get() \u540e yield \u51fa\u53bb\u3002\u8fd9\u6837\u5e7f\u64ad\u5668\u4e0d\u7528\u7b49\u5ba2\u6237\u7aef&#xff0c;\u53d1\u9001\u4e5f\u4e0d\u4f1a\u963b\u585e\u5e7f\u64ad\u5faa\u73af\u3002<\/li>\n<\/ul>\n<h4>3.3.4 SSE \u7aef\u70b9<\/h4>\n<p><span class=\"token decorator annotation punctuation\">&#064;router<span class=\"token punctuation\">.<\/span>get<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\/sse\/orders&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n<span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">sse_orders<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> StreamingResponse<span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u5efa\u7acb SSE \u8fde\u63a5, \u6301\u7eed\u63a5\u6536 orders \u4e8b\u4ef6.&#034;&#034;&#034;<\/span><br \/>\n    queue<span class=\"token punctuation\">:<\/span> asyncio<span class=\"token punctuation\">.<\/span>Queue<span class=\"token punctuation\">[<\/span>_QueueItem<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> asyncio<span class=\"token punctuation\">.<\/span>Queue<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    sse_clients<span class=\"token punctuation\">.<\/span>add<span class=\"token punctuation\">(<\/span>queue<span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u6bcf\u4e2a\u5ba2\u6237\u7aef\u8fde\u8fdb\u6765&#xff0c;\u5c31\u65b0\u5efa\u4e00\u4e2a\u4e13\u5c5e Queue&#xff0c;\u52a0\u8fdb sse_clients \u96c6\u5408&#xff1b;<\/li>\n<li>\u6ce8\u610f\u662f async def&#xff1a;\u56e0\u4e3a\u91cc\u9762\u8981 await queue.get()\u3002<\/li>\n<\/ul>\n<h4>3.3.5 \u4e8b\u4ef6\u6d41\u751f\u6210\u5668<\/h4>\n<p>    <span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">event_stream<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token comment\"># \u9996\u6b21\u53d1 hello, \u8ba9\u524d\u7aef\u7acb\u5373\u611f\u77e5\u8fde\u63a5\u6210\u529f\u5e76\u62ff\u5230\u83dc\u5355<\/span><br \/>\n            hello <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;menu&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">[<\/span>m<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token keyword\">for<\/span> m <span class=\"token keyword\">in<\/span> MENU<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;statuses&#034;<\/span><span class=\"token punctuation\">:<\/span> STATUSES<span class=\"token punctuation\">}<\/span><br \/>\n            <span class=\"token keyword\">yield<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;event: hello\\\\ndata: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>json<span class=\"token punctuation\">.<\/span>dumps<span class=\"token punctuation\">(<\/span>hello<span class=\"token punctuation\">,<\/span> ensure_ascii<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">\\\\n\\\\n&#034;<\/span><\/span><\/p>\n<p>            <span class=\"token comment\"># \u4e3b\u5faa\u73af: \u4ece Queue \u53d6\u4e8b\u4ef6\u5e76\u4ee5 SSE \u5e27\u683c\u5f0f\u5199\u51fa<\/span><br \/>\n            <span class=\"token keyword\">while<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                item <span class=\"token operator\">&#061;<\/span> <span class=\"token keyword\">await<\/span> queue<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">yield<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;event: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>item<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#039;event&#039;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">\\\\ndata: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>item<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#039;data&#039;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">\\\\n\\\\n&#034;<\/span><\/span><br \/>\n        <span class=\"token keyword\">finally<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token comment\"># \u5ba2\u6237\u7aef\u65ad\u5f00 \/ \u5f02\u5e38 -&gt; \u9000\u8ba2, \u907f\u514d\u6cc4\u6f0f<\/span><br \/>\n            sse_clients<span class=\"token punctuation\">.<\/span>discard<span class=\"token punctuation\">(<\/span>queue<span class=\"token punctuation\">)<\/span><\/p>\n<p>\u8fd9\u662f SSE \u7684\u6838\u5fc3&#xff0c;\u9010\u884c\u770b&#xff1a;<\/p>\n<li>\n<p>\u5148\u53d1 hello&#xff1a;\u8fde\u63a5\u521a\u5efa\u7acb&#xff0c;\u7acb\u523b yield \u4e00\u5e27 hello \u4e8b\u4ef6&#xff0c;\u628a\u83dc\u5355\u548c\u72b6\u6001\u5217\u8868\u7ed9\u524d\u7aef\u3002\u524d\u7aef\u62ff\u5230\u540e\u5c31\u80fd\u6e32\u67d3\u72b6\u6001\u8272\u5757\u3001\u663e\u793a\u83dc\u5355\u3002\u8fd9\u6837\u524d\u7aef\u4e0d\u7528\u989d\u5916\u53d1\u8bf7\u6c42\u62ff\u83dc\u5355&#xff1b;<\/p>\n<\/li>\n<li>\n<p>SSE \u5e27\u683c\u5f0f&#xff1a;<\/p>\n<p> event: hello\\\\n<br \/>\ndata: {&#034;menu&#034;: [&#8230;], &#034;statuses&#034;: [&#8230;]} \\\\n<br \/>\n\\\\n<\/p>\n<ul>\n<li>event: \u884c&#xff1a;\u4e8b\u4ef6\u540d&#xff1b;<\/li>\n<li>data: \u884c&#xff1a;\u6570\u636e&#xff08;\u4e00\u6bb5 JSON \u5b57\u7b26\u4e32&#xff09;&#xff1b;<\/li>\n<li>\u672b\u5c3e\u4e24\u4e2a \\\\n&#xff1a;\u4e00\u4e2a\u7ed3\u675f data \u884c&#xff0c;\u4e00\u4e2a\u7a7a\u884c\u8868\u793a\u8fd9\u4e00\u5e27\u7ed3\u675f&#xff08;SSE \u89c4\u8303\u8981\u6c42&#xff09;&#xff1b;<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u4e3b\u5faa\u73af&#xff1a;await queue.get() \u963b\u585e\u7b49\u5f85&#xff0c;\u76f4\u5230\u5e7f\u64ad\u5668\u5f80\u8fd9\u4e2a Queue \u91cc put \u4e86\u4e8b\u4ef6\u3002\u62ff\u5230\u540e\u62fc\u6210 SSE \u5e27 yield \u51fa\u53bb&#xff0c;\u53d1\u7ed9\u6d4f\u89c8\u5668&#xff1b;<\/p>\n<\/li>\n<li>\n<p>finally \u9000\u8ba2&#xff1a;\u5ba2\u6237\u7aef\u65ad\u5f00&#xff08;\u5173\u9875\u9762\u3001\u7f51\u7edc\u65ad\u4e86&#xff09;\u4f1a\u8ba9 yield \u629b GeneratorExit \u6216\u5f02\u5e38&#xff0c;\u8fdb\u5165 finally\u3002\u8fd9\u91cc sse_clients.discard(queue) \u628a\u81ea\u5df1\u4ece\u96c6\u5408\u79fb\u9664\u3002\u8fd9\u4e00\u6b65\u81f3\u5173\u91cd\u8981\u2014\u2014\u5982\u679c\u4e0d\u79fb\u9664&#xff0c;\u5e7f\u64ad\u5668\u8fd8\u4f1a\u7ee7\u7eed\u5f80\u8fd9\u4e2a\u300c\u6b7b\u8fde\u63a5\u300d\u7684 Queue \u91cc\u585e\u6570\u636e&#xff0c;Queue \u65e0\u9650\u589e\u957f &#061; \u5185\u5b58\u6cc4\u6f0f\u3002<\/p>\n<\/li>\n<p>json.dumps(hello, ensure_ascii&#061;False)&#xff1a;\u8ba9\u4e2d\u6587&#xff08;\u73cd\u73e0\u5976\u8336\u7b49&#xff09;\u539f\u6837\u8f93\u51fa&#xff0c;\u4e0d\u88ab\u8f6c\u6210 \u73cd\u73e0\u3002<\/p>\n<h4>3.3.6 \u8fd4\u56de StreamingResponse<\/h4>\n<p>    <span class=\"token keyword\">return<\/span> StreamingResponse<span class=\"token punctuation\">(<\/span><br \/>\n        event_stream<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        media_type<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;text\/event-stream&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        headers<span class=\"token operator\">&#061;<\/span><span class=\"token punctuation\">{<\/span><br \/>\n            <span class=\"token string\">&#034;Cache-Control&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;no-cache&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string\">&#034;Connection&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;keep-alive&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string\">&#034;X-Accel-Buffering&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;no&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    <span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>event_stream()&#xff1a;\u6ce8\u610f\u8fd9\u91cc\u8c03\u7528\u4e86\u751f\u6210\u5668\u51fd\u6570&#xff08;\u5e26 ()&#xff09;&#xff0c;\u4f20\u8fdb\u53bb\u7684\u662f\u751f\u6210\u5668\u5bf9\u8c61&#xff1b;<\/li>\n<li>media_type&#061;&#034;text\/event-stream&#034;&#xff1a;SSE \u7684\u6807\u5fd7&#xff0c;\u6d4f\u89c8\u5668\u770b\u5230\u8fd9\u4e2a\u624d\u4f1a\u6309 SSE \u89e3\u6790&#xff0c;EventSource \u624d\u80fd\u6b63\u5e38\u5de5\u4f5c&#xff1b;<\/li>\n<li>\u4e09\u4e2a\u54cd\u5e94\u5934&#xff1a;\n<ul>\n<li>Cache-Control: no-cache&#xff1a;\u522b\u7f13\u5b58\u4e8b\u4ef6\u6d41&#xff0c;\u6bcf\u6b21\u90fd\u8981\u65b0\u7684&#xff1b;<\/li>\n<li>Connection: keep-alive&#xff1a;\u4fdd\u6301\u957f\u8fde\u63a5&#xff0c;\u4e0d\u8981\u53d1\u5b8c\u5c31\u65ad&#xff1b;<\/li>\n<li>X-Accel-Buffering: no&#xff1a;\u7ed9 nginx \u770b\u7684\u3002\u5982\u679c\u90e8\u7f72\u5728 nginx \u540e\u9762&#xff0c;nginx \u9ed8\u8ba4\u4f1a\u7f13\u51b2\u54cd\u5e94\u518d\u6279\u91cf\u53d1&#xff0c;\u8fd9\u4f1a\u8ba9 SSE \u5931\u53bb\u5b9e\u65f6\u6027\u3002\u8fd9\u884c\u544a\u8bc9 nginx\u300c\u522b\u7f13\u51b2\u6211&#xff0c;\u6536\u5230\u5c31\u8f6c\u53d1\u300d\u3002<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<hr \/>\n<h3>3.4 \u6570\u636e\u6d41\u56de\u987e<\/h3>\n<p>\u6d4f\u89c8\u5668 EventSource(&#039;\/sse\/orders&#039;)<br \/>\n            \u2502 HTTP GET, Upgrade \u957f\u8fde\u63a5<br \/>\n            \u25bc<br \/>\nsse_orders()  \u2192  \u65b0\u5efa Queue \u52a0\u5165 sse_clients  \u2192  \u8fd4\u56de StreamingResponse<br \/>\n            \u2502<br \/>\n            \u2502  event_stream() \u751f\u6210\u5668\u6301\u7eed\u8fd0\u884c:<br \/>\n            \u2502   1. \u5148 yield hello \u5e27<br \/>\n            \u2502   2. \u5faa\u73af await queue.get()  \u2192  yield orders \u5e27<br \/>\n            \u2502<br \/>\n            \u25bc<br \/>\n\u6d4f\u89c8\u5668\u6536\u5230 event:hello  \u2192 \u663e\u793a\u83dc\u5355<br \/>\n\u6d4f\u89c8\u5668\u6536\u5230 event:orders \u2192 \u5237\u65b0\u8ba2\u5355\u5361\u7247<br \/>\n            \u2502<br \/>\n&#xff08;\u65ad\u5f00\u65f6&#xff09; finally: sse_clients.discard(queue)  \u2190 \u9632\u6cc4\u6f0f<\/p>\n<p>\u8c01\u5f80 Queue \u91cc put&#xff1f;\u7b54\u6848\u662f\u7b2c 5 \u7ae0\u7684\u5e7f\u64ad\u5668\u3002\u5b83\u6bcf 0.8s \u8c03 advance()&#xff0c;\u7136\u540e\u628a\u7ed3\u679c put \u8fdb\u6bcf\u4e00\u4e2a sse_clients \u7684 Queue\u3002<\/p>\n<h3>3.5 \u52a8\u624b\u9a8c\u8bc1&#xff08;\u9700\u8981\u5148\u8df3\u5230\u7b2c 6 \u7ae0\u628a app.py \u5199\u5b8c&#xff09;<\/h3>\n<p>\u8fd9\u4e00\u7ae0\u7684\u4ee3\u7801\u5355\u72ec\u8fd8\u4e0d\u80fd\u8dd1&#xff08;\u7f3a\u5165\u53e3&#xff09;\u3002\u5982\u679c\u4f60\u5df2\u7ecf\u6309\u987a\u5e8f\u5199\u5230\u4e86\u7b2c 6 \u7ae0&#xff0c;\u53ef\u4ee5\u8fd9\u6837\u9a8c\u8bc1 SSE&#xff1a;<\/p>\n<p><span class=\"token comment\"># \u542f\u52a8\u670d\u52a1&#xff08;\u7b2c 6 \u7ae0\u7684\u547d\u4ee4&#xff09;<\/span><br \/>\nuv run python <span class=\"token parameter variable\">-m<\/span> uvicorn src.app:app <span class=\"token parameter variable\">&#8211;host<\/span> <span class=\"token number\">127.0<\/span>.0.1 <span class=\"token parameter variable\">&#8211;port<\/span> <span class=\"token number\">8000<\/span> <span class=\"token parameter variable\">&#8211;reload<\/span><\/p>\n<p><span class=\"token comment\"># \u53e6\u5f00\u7ec8\u7aef&#xff0c;\u7528 curl \u8fde SSE&#xff08;-N \u8868\u793a\u4e0d\u7f13\u51b2&#xff09;<\/span><br \/>\n<span class=\"token function\">curl<\/span> <span class=\"token parameter variable\">-N<\/span> http:\/\/127.0.0.1:8000\/sse\/orders<\/p>\n<p>\u4f60\u4f1a\u6301\u7eed\u770b\u5230&#xff1a;<\/p>\n<p>event: hello<br \/>\ndata: {&#034;menu&#034;: [&#034;\u73cd\u73e0\u5976\u8336&#034;, &#034;\u6768\u679d\u7518\u9732&#034;, &#8230;], &#034;statuses&#034;: [&#034;\u5f85\u5236\u4f5c&#034;, &#034;\u5236\u4f5c\u4e2d&#034;, &#034;\u5df2\u5b8c\u6210&#034;, &#034;\u5df2\u53d6\u9910&#034;]}<\/p>\n<p>event: orders<br \/>\ndata: {&#034;time&#034;: &#034;&#8230;&#034;, &#034;orders&#034;: [{&#8230;}, {&#8230;}]}<\/p>\n<p>event: orders<br \/>\ndata: {&#034;time&#034;: &#034;&#8230;&#034;, &#034;orders&#034;: [{&#8230;}, {&#8230;}]}<br \/>\n&#8230;<\/p>\n<p>\u6bcf 0.8 \u79d2\u4e00\u5e27 orders&#xff0c;\u6309 Ctrl&#043;C \u9000\u51fa\u3002<\/p>\n<h3>3.6 \u5c0f\u7ed3<\/h3>\n<table>\n<tr>\u8981\u70b9\u8bf4\u660e<\/tr>\n<tbody>\n<tr>\n<td>\u534f\u8bae<\/td>\n<td>HTTP &#043; text\/event-stream<\/td>\n<\/tr>\n<tr>\n<td>\u65b9\u5411<\/td>\n<td>\u670d\u52a1\u5668 \u2192 \u6d4f\u89c8\u5668&#xff08;\u5355\u5411&#xff09;<\/td>\n<\/tr>\n<tr>\n<td>\u6d4f\u89c8\u5668 API<\/td>\n<td>new EventSource(url)<\/td>\n<\/tr>\n<tr>\n<td>\u91cd\u8fde<\/td>\n<td>\u6d4f\u89c8\u5668\u81ea\u52a8\u91cd\u8fde<\/td>\n<\/tr>\n<tr>\n<td>\u6bcf\u8fde\u63a5\u7f13\u51b2<\/td>\n<td>\u4e00\u4e2a asyncio.Queue<\/td>\n<\/tr>\n<tr>\n<td>\u5e27\u683c\u5f0f<\/td>\n<td>event: \/ data: \/ \u7a7a\u884c<\/td>\n<\/tr>\n<tr>\n<td>\u9632\u6cc4\u6f0f<\/td>\n<td>finally \u91cc discard<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<hr \/>\n<p>\u4e0b\u4e00\u7ae0 \u2192 04-WebSocket\u6a21\u5757-ws.md&#xff1a;\u7528 WebSocket \u5b9e\u73b0\u53cc\u5411\u901a\u9053&#xff0c;\u8ba9\u524d\u7aef\u80fd\u53d1\u547d\u4ee4\u3002<\/p>\n<hr \/>\n<h2>\u7b2c 4 \u7ae0 \u00b7 WebSocket \u6a21\u5757 ws.py<\/h2>\n<h3>\u672c\u7ae0\u76ee\u6807<\/h3>\n<p>\u5b9e\u73b0\u9879\u76ee\u7684\u7b2c\u4e8c\u4e2a\u4f20\u8f93\u6a21\u5757\u2014\u2014WebSocket&#xff08;\u53cc\u5411\u901a\u9053&#xff09;\u3002\u548c SSE \u7684\u300c\u53ea\u63a8\u4e0d\u6536\u300d\u4e0d\u540c&#xff0c;WebSocket \u8ba9\u524d\u7aef\u80fd\u4e3b\u52a8\u53d1\u547d\u4ee4&#xff0c;\u670d\u52a1\u5668\u7ed9\u660e\u786e\u56de\u6267\u3002\u5b66\u5b8c\u672c\u7ae0\u4f60\u5c06\u7406\u89e3&#xff1a;<\/p>\n<ul>\n<li>WebSocket \u5728 FastAPI \u91cc\u7684\u5199\u6cd5&#xff08;&#064;router.websocket\u3001accept\u3001receive_text\u3001send_text&#xff09;&#xff1b;<\/li>\n<li>\u547d\u4ee4\u5206\u53d1\u6a21\u5f0f&#xff1a;cmd &#043; arg&#xff0c;\u6bcf\u79cd\u547d\u4ee4\u4e00\u4e2a\u5206\u652f&#xff0c;\u6bcf\u6761\u547d\u4ee4\u90fd\u6709\u56de\u6267&#xff1b;<\/li>\n<li>\u7528 TypedDict \u7ed9\u6bcf\u79cd\u6d88\u606f\u5b9a\u4e49\u7c7b\u578b&#xff0c;\u524d\u7aef\u540e\u7aef\u7ea6\u5b9a\u6e05\u6670&#xff1b;<\/li>\n<li>WebSocketDisconnect \u5f02\u5e38 &#043; finally \u6e05\u7406\u8fde\u63a5&#xff0c;\u9632\u6cc4\u6f0f\u3002<\/li>\n<\/ul>\n<hr \/>\n<h3>4.1 \u5148\u7406\u89e3 WebSocket \u662f\u4ec0\u4e48<\/h3>\n<p>WebSocket \u662f HTML5 \u7684\u5168\u53cc\u5de5\u534f\u8bae&#xff1a;<\/p>\n<ul>\n<li>\u63e1\u624b\u9636\u6bb5\u7528 HTTP&#xff0c;\u4e4b\u540e\u300c\u5347\u7ea7\u300d\u6210 ws:\/\/&#xff0c;\u8fde\u63a5\u4fdd\u6301&#xff0c;\u53cc\u65b9\u53ef\u968f\u65f6\u4e92\u53d1\u6d88\u606f&#xff1b;<\/li>\n<li>\u6d4f\u89c8\u5668\u7528 new WebSocket(url) \u8fde\u63a5&#xff08;\u4e0d\u81ea\u52a8\u91cd\u8fde&#xff0c;\u65ad\u4e86\u8981\u81ea\u5df1\u91cd\u8fde&#xff0c;\u7b2c 7 \u7ae0\u524d\u7aef\u4f1a\u5904\u7406&#xff09;&#xff1b;<\/li>\n<li>\u9002\u5408\u6709\u4ea4\u4e92\u7684\u573a\u666f&#xff1a;\u804a\u5929\u3001\u534f\u4f5c\u7f16\u8f91\u3001\u6211\u4eec\u7684\u300c\u5e97\u5458\u64cd\u4f5c\u53f0\u300d&#xff08;\u53d1\u547d\u4ee4 &#043; \u62ff\u56de\u6267&#xff09;\u3002<\/li>\n<\/ul>\n<p>\u672c\u9879\u76ee\u91cc WebSocket \u652f\u6301\u56db\u79cd\u547d\u4ee4&#xff1a;<\/p>\n<table>\n<tr>\u547d\u4ee4\u542b\u4e49\u670d\u52a1\u5668\u56de\u6267<\/tr>\n<tbody>\n<tr>\n<td>ping<\/td>\n<td>\u63a2\u6d3b&#xff0c;\u6d4b\u5ef6\u8fdf<\/td>\n<td>{&#034;type&#034;:&#034;pong&#034;,&#034;time&#034;:&#034;&#8230;&#034;}<\/td>\n<\/tr>\n<tr>\n<td>add<\/td>\n<td>\u7acb\u523b\u52a0\u4e00\u676f\u968f\u673a\u8ba2\u5355<\/td>\n<td>{&#034;type&#034;:&#034;added&#034;,&#034;order&#034;:{&#8230;}}<\/td>\n<\/tr>\n<tr>\n<td>pickup<\/td>\n<td>\u6309 id \u53d6\u9910&#xff08;\u4ec5\u300c\u5df2\u5b8c\u6210\u300d\u53ef\u53d6&#xff09;<\/td>\n<td>{&#034;type&#034;:&#034;picked&#034;,&#034;order&#034;:{&#8230;}} \u6216 {&#034;type&#034;:&#034;error&#034;,&#8230;}<\/td>\n<\/tr>\n<tr>\n<td>snapshot<\/td>\n<td>\u62c9\u4e00\u6b21\u5f53\u524d\u5feb\u7167<\/td>\n<td>{&#034;type&#034;:&#034;snapshot&#034;,&#034;time&#034;:&#034;&#8230;&#034;,&#034;orders&#034;:[&#8230;]}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>4.2 \u539f\u59cb\u5b8c\u6574\u4ee3\u7801<\/h3>\n<p>\u65b0\u5efa\u6587\u4ef6 src\/ws.py&#xff0c;\u5b8c\u6574\u7167\u6284&#xff1a;<\/p>\n<p><span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6559\u5b66\u6a21\u5757 2: WebSocket \u53cc\u5411\u901a\u9053.<\/p>\n<p>\u5173\u952e\u70b9<br \/>\n&#8212;&#8212;<br \/>\n&#8211; \u5168\u53cc\u5de5: \u5ba2\u6237\u7aef\u548c\u670d\u52a1\u7aef\u90fd\u53ef\u4e3b\u52a8\u53d1\u9001\u6d88\u606f<br \/>\n&#8211; \u63a5\u53d7\u8fde\u63a5\u540e\u52a0\u5165 ws_clients \u96c6\u5408, \u5e7f\u64ad\u5668\u7edf\u4e00\u63a8\u9001<br \/>\n&#8211; \u63a5\u6536\u5ba2\u6237\u7aef\u547d\u4ee4: ping \/ add \/ pickup \/ snapshot, \u6bcf\u6761\u547d\u4ee4\u90fd\u6709\u660e\u786e\u56de\u6267<br \/>\n&#8211; WebSocketDisconnect \u5f02\u5e38\u8868\u793a\u5ba2\u6237\u7aef\u4e3b\u52a8\u5173\u95ed, finally \u6e05\u7406\u8fde\u63a5<br \/>\n&#034;&#034;&#034;<\/span><\/p>\n<p><span class=\"token keyword\">import<\/span> json<br \/>\n<span class=\"token keyword\">from<\/span> datetime <span class=\"token keyword\">import<\/span> UTC<span class=\"token punctuation\">,<\/span> datetime<br \/>\n<span class=\"token keyword\">from<\/span> typing <span class=\"token keyword\">import<\/span> TypedDict<\/p>\n<p><span class=\"token keyword\">from<\/span> fastapi <span class=\"token keyword\">import<\/span> APIRouter<span class=\"token punctuation\">,<\/span> WebSocket<span class=\"token punctuation\">,<\/span> WebSocketDisconnect<\/p>\n<p><span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>models <span class=\"token keyword\">import<\/span> MENU<span class=\"token punctuation\">,<\/span> STATUSES<span class=\"token punctuation\">,<\/span> Order<span class=\"token punctuation\">,<\/span> Snapshot<span class=\"token punctuation\">,<\/span> new_order<span class=\"token punctuation\">,<\/span> orders<span class=\"token punctuation\">,<\/span> snapshot<\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">HelloMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    menu<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">]<\/span><br \/>\n    statuses<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">]<\/span><br \/>\n    orders<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span>Order<span class=\"token punctuation\">]<\/span><\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">PongMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    time<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">AddedMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    order<span class=\"token punctuation\">:<\/span> Order<\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">PickedMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    order<span class=\"token punctuation\">:<\/span> Order<\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">SnapshotMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    time<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    orders<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span>Order<span class=\"token punctuation\">]<\/span><\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">ErrorMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    error<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><\/p>\n<p>router <span class=\"token operator\">&#061;<\/span> APIRouter<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token comment\"># \u6240\u6709\u5df2\u8fde\u63a5\u7684 WebSocket \u5ba2\u6237\u7aef (\u7531 broadcaster \u5199\u5165)<\/span><br \/>\nws_clients<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">set<\/span><span class=\"token punctuation\">[<\/span>WebSocket<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">set<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">now_iso<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token keyword\">return<\/span> datetime<span class=\"token punctuation\">.<\/span>now<span class=\"token punctuation\">(<\/span>UTC<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>isoformat<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token decorator annotation punctuation\">&#064;router<span class=\"token punctuation\">.<\/span>websocket<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\/ws\/orders&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n<span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">ws_orders<\/span><span class=\"token punctuation\">(<\/span>ws<span class=\"token punctuation\">:<\/span> WebSocket<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> <span class=\"token boolean\">None<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u5efa\u7acb WS \u8fde\u63a5, \u5904\u7406\u5ba2\u6237\u7aef\u547d\u4ee4.&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token keyword\">await<\/span> ws<span class=\"token punctuation\">.<\/span>accept<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    ws_clients<span class=\"token punctuation\">.<\/span>add<span class=\"token punctuation\">(<\/span>ws<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span>msg<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">dict<\/span><span class=\"token punctuation\">[<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">object<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> <span class=\"token boolean\">None<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">await<\/span> ws<span class=\"token punctuation\">.<\/span>send_text<span class=\"token punctuation\">(<\/span>json<span class=\"token punctuation\">.<\/span>dumps<span class=\"token punctuation\">(<\/span>msg<span class=\"token punctuation\">,<\/span> ensure_ascii<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token comment\"># \u63e1\u624b\u6210\u529f\u540e\u7acb\u5373\u53d1 hello, \u628a\u83dc\u5355\u548c\u5f53\u524d\u5feb\u7167\u7ed9\u5ba2\u6237\u7aef<\/span><br \/>\n        <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>HelloMsg<span class=\"token punctuation\">(<\/span><br \/>\n            <span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;hello&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            menu<span class=\"token operator\">&#061;<\/span><span class=\"token punctuation\">[<\/span>m<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token keyword\">for<\/span> m <span class=\"token keyword\">in<\/span> MENU<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            statuses<span class=\"token operator\">&#061;<\/span>STATUSES<span class=\"token punctuation\">,<\/span><br \/>\n            orders<span class=\"token operator\">&#061;<\/span><span class=\"token builtin\">sorted<\/span><span class=\"token punctuation\">(<\/span>orders<span class=\"token punctuation\">.<\/span>values<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> key<span class=\"token operator\">&#061;<\/span><span class=\"token keyword\">lambda<\/span> o<span class=\"token punctuation\">:<\/span> <span class=\"token operator\">&#8211;<\/span>o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;id&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        <span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u547d\u4ee4\u5206\u53d1<\/span><br \/>\n        <span class=\"token keyword\">while<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            raw <span class=\"token operator\">&#061;<\/span> <span class=\"token keyword\">await<\/span> ws<span class=\"token punctuation\">.<\/span>receive_text<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                msg <span class=\"token operator\">&#061;<\/span> json<span class=\"token punctuation\">.<\/span>loads<span class=\"token punctuation\">(<\/span>raw<span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">except<\/span> json<span class=\"token punctuation\">.<\/span>JSONDecodeError<span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>ErrorMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> error<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;invalid json&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">continue<\/span><\/p>\n<p>            cmd <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>msg<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;cmd&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>lower<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            arg <span class=\"token operator\">&#061;<\/span> msg<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;arg&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>            <span class=\"token keyword\">if<\/span> cmd <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;ping&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>PongMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;pong&#034;<\/span><span class=\"token punctuation\">,<\/span> time<span class=\"token operator\">&#061;<\/span>now_iso<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;add&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                o <span class=\"token operator\">&#061;<\/span> new_order<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                orders<span class=\"token punctuation\">[<\/span>o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;id&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> o<br \/>\n                <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>AddedMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;added&#034;<\/span><span class=\"token punctuation\">,<\/span> order<span class=\"token operator\">&#061;<\/span>o<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;pickup&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    oid <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">(<\/span>arg<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">except<\/span> <span class=\"token punctuation\">(<\/span>TypeError<span class=\"token punctuation\">,<\/span> ValueError<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>ErrorMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> error<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;arg must be int order_id&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                    <span class=\"token keyword\">continue<\/span><br \/>\n                o <span class=\"token operator\">&#061;<\/span> orders<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span>oid<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> o<span class=\"token punctuation\">:<\/span><br \/>\n                    <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>ErrorMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> error<span class=\"token operator\">&#061;<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;order <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>oid<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> not found&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">elif<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">!&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u5b8c\u6210&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>ErrorMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> error<span class=\"token operator\">&#061;<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;order <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>oid<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> not ready&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u53d6\u9910&#034;<\/span><br \/>\n                    <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>PickedMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;picked&#034;<\/span><span class=\"token punctuation\">,<\/span> order<span class=\"token operator\">&#061;<\/span>o<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;snapshot&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                snap<span class=\"token punctuation\">:<\/span> Snapshot <span class=\"token operator\">&#061;<\/span> snapshot<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>SnapshotMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;snapshot&#034;<\/span><span class=\"token punctuation\">,<\/span> time<span class=\"token operator\">&#061;<\/span>snap<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;time&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> orders<span class=\"token operator\">&#061;<\/span>snap<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;orders&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>ErrorMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> error<span class=\"token operator\">&#061;<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;unknown cmd: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>cmd<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">except<\/span> WebSocketDisconnect<span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">pass<\/span><br \/>\n    <span class=\"token keyword\">finally<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        ws_clients<span class=\"token punctuation\">.<\/span>discard<span class=\"token punctuation\">(<\/span>ws<span class=\"token punctuation\">)<\/span><\/p>\n<hr \/>\n<h3>4.3 \u9010\u6bb5\u8bb2\u89e3<\/h3>\n<h4>4.3.1 \u5bfc\u5165<\/h4>\n<p><span class=\"token keyword\">import<\/span> json<br \/>\n<span class=\"token keyword\">from<\/span> datetime <span class=\"token keyword\">import<\/span> UTC<span class=\"token punctuation\">,<\/span> datetime<br \/>\n<span class=\"token keyword\">from<\/span> typing <span class=\"token keyword\">import<\/span> TypedDict<\/p>\n<p><span class=\"token keyword\">from<\/span> fastapi <span class=\"token keyword\">import<\/span> APIRouter<span class=\"token punctuation\">,<\/span> WebSocket<span class=\"token punctuation\">,<\/span> WebSocketDisconnect<\/p>\n<p><span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>models <span class=\"token keyword\">import<\/span> MENU<span class=\"token punctuation\">,<\/span> STATUSES<span class=\"token punctuation\">,<\/span> Order<span class=\"token punctuation\">,<\/span> Snapshot<span class=\"token punctuation\">,<\/span> new_order<span class=\"token punctuation\">,<\/span> orders<span class=\"token punctuation\">,<\/span> snapshot<\/p>\n<ul>\n<li>WebSocket&#xff1a;FastAPI \u7684 WebSocket \u8fde\u63a5\u5bf9\u8c61&#xff0c;\u51fd\u6570\u53c2\u6570\u6ce8\u89e3\u4e3a WebSocket \u65f6 FastAPI \u81ea\u52a8\u6ce8\u5165&#xff1b;<\/li>\n<li>WebSocketDisconnect&#xff1a;Starlette \u63d0\u4f9b\u7684\u5f02\u5e38&#xff0c;\u5ba2\u6237\u7aef\u4e3b\u52a8\u65ad\u5f00\u65f6 receive_text() \u4f1a\u629b\u5b83&#xff1b;<\/li>\n<li>\u4ece models \u5bfc\u5165\u4e00\u5806&#xff1a;\u83dc\u5355\u3001\u72b6\u6001\u3001\u8ba2\u5355\u7c7b\u578b\u3001new_order&#xff08;\u52a0\u5355\u7528&#xff09;\u3001orders&#xff08;\u53d6\/\u6539\u8ba2\u5355\u7528&#xff09;\u3001snapshot&#xff08;\u62c9\u5feb\u7167\u7528&#xff09;\u3002<\/li>\n<\/ul>\n<h4>4.3.2 \u6d88\u606f\u7c7b\u578b&#xff08;\u524d\u7aef\/\u540e\u7aef\u7684\u5951\u7ea6&#xff09;<\/h4>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">HelloMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    menu<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">]<\/span><br \/>\n    statuses<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">]<\/span><br \/>\n    orders<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span>Order<span class=\"token punctuation\">]<\/span><\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">PongMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    time<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">AddedMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    order<span class=\"token punctuation\">:<\/span> Order<\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">PickedMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    order<span class=\"token punctuation\">:<\/span> Order<\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">SnapshotMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    time<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    orders<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">[<\/span>Order<span class=\"token punctuation\">]<\/span><\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">ErrorMsg<\/span><span class=\"token punctuation\">(<\/span>TypedDict<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token builtin\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><br \/>\n    error<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">str<\/span><\/p>\n<ul>\n<li>\u6bcf\u79cd\u670d\u52a1\u5668\u2192\u5ba2\u6237\u7aef\u7684\u6d88\u606f\u90fd\u5b9a\u4e49\u4e00\u4e2a TypedDict&#xff0c;\u6240\u6709\u6d88\u606f\u90fd\u6709\u4e00\u4e2a type \u5b57\u6bb5\u8868\u793a\u6d88\u606f\u7c7b\u578b&#xff1b;<\/li>\n<li>\u8fd9\u662f WebSocket \u901a\u4fe1\u7684\u5e38\u89c1\u6a21\u5f0f&#xff1a;\u7528 type \u5b57\u6bb5\u505a\u6d88\u606f\u5206\u53d1&#xff0c;\u524d\u7aef ws.onmessage \u91cc switch(msg.type)&#xff1b;<\/li>\n<li>HelloMsg&#xff1a;\u63e1\u624b\u540e\u53d1\u7684\u6b22\u8fce\u6d88\u606f&#xff08;\u83dc\u5355 &#043; \u5f53\u524d\u6240\u6709\u8ba2\u5355&#xff09;&#xff1b;<\/li>\n<li>PongMsg&#xff1a;ping \u7684\u56de\u6267&#xff1b;<\/li>\n<li>AddedMsg&#xff1a;add \u7684\u56de\u6267&#xff08;\u65b0\u8ba2\u5355\u8be6\u60c5&#xff09;&#xff1b;<\/li>\n<li>PickedMsg&#xff1a;pickup \u6210\u529f\u7684\u56de\u6267&#xff1b;<\/li>\n<li>SnapshotMsg&#xff1a;snapshot \u7684\u56de\u6267&#xff1b;<\/li>\n<li>ErrorMsg&#xff1a;\u4efb\u4f55\u9519\u8bef\u7684\u56de\u6267\u3002<\/li>\n<\/ul>\n<p>\u4e3a\u4ec0\u4e48\u7528 TypedDict \u800c\u4e0d\u662f dataclass \u6216 pydantic.BaseModel&#xff1f;\u56e0\u4e3a\u8fd9\u91cc\u6d88\u606f\u76f4\u63a5 json.dumps \u6210 dict&#xff0c;TypedDict \u96f6\u8fd0\u884c\u65f6\u5f00\u9500&#xff0c;\u7eaf\u7cb9\u662f\u7c7b\u578b\u63d0\u793a&#xff0c;\u6700\u8f7b\u91cf\u3002<\/p>\n<h4>4.3.3 \u8def\u7531 &#043; \u5ba2\u6237\u7aef\u96c6\u5408<\/h4>\n<p>router <span class=\"token operator\">&#061;<\/span> APIRouter<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token comment\"># \u6240\u6709\u5df2\u8fde\u63a5\u7684 WebSocket \u5ba2\u6237\u7aef (\u7531 broadcaster \u5199\u5165)<\/span><br \/>\nws_clients<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">set<\/span><span class=\"token punctuation\">[<\/span>WebSocket<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">set<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u548c SSE \u4e00\u6837\u7528 APIRouter&#xff1b;<\/li>\n<li>ws_clients&#xff1a;\u6240\u6709\u5f53\u524d WS \u8fde\u63a5\u7684\u96c6\u5408\u3002\u5e7f\u64ad\u5668&#xff08;\u7b2c 5 \u7ae0&#xff09;\u4f1a\u904d\u5386\u5b83 send_text&#xff1b;<\/li>\n<li>\u6ce8\u610f\u8fd9\u91cc\u5b58\u7684\u662f**WebSocket \u5bf9\u8c61\u672c\u8eab**&#xff0c;\u4e0d\u50cf SSE \u5b58 Queue\u3002\u56e0\u4e3a WebSocket \u539f\u751f\u652f\u6301\u5f02\u6b65 send_text&#xff0c;\u53ef\u4ee5\u76f4\u63a5\u53d1\u3002<\/li>\n<\/ul>\n<h4>4.3.4 \u63a5\u53d7\u8fde\u63a5 &#043; \u5185\u90e8 send \u8f85\u52a9<\/h4>\n<p><span class=\"token decorator annotation punctuation\">&#064;router<span class=\"token punctuation\">.<\/span>websocket<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\/ws\/orders&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n<span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">ws_orders<\/span><span class=\"token punctuation\">(<\/span>ws<span class=\"token punctuation\">:<\/span> WebSocket<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> <span class=\"token boolean\">None<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u5efa\u7acb WS \u8fde\u63a5, \u5904\u7406\u5ba2\u6237\u7aef\u547d\u4ee4.&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token keyword\">await<\/span> ws<span class=\"token punctuation\">.<\/span>accept<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    ws_clients<span class=\"token punctuation\">.<\/span>add<span class=\"token punctuation\">(<\/span>ws<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span>msg<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">dict<\/span><span class=\"token punctuation\">[<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">object<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> <span class=\"token boolean\">None<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">await<\/span> ws<span class=\"token punctuation\">.<\/span>send_text<span class=\"token punctuation\">(<\/span>json<span class=\"token punctuation\">.<\/span>dumps<span class=\"token punctuation\">(<\/span>msg<span class=\"token punctuation\">,<\/span> ensure_ascii<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>&#064;router.websocket(&#8230;)&#xff1a;\u58f0\u660e\u8fd9\u662f\u4e00\u4e2a WebSocket \u8def\u7531&#xff08;\u4e0d\u662f HTTP GET&#xff09;&#xff1b;<\/li>\n<li>await ws.accept()&#xff1a;\u5fc5\u987b\u5148 accept&#xff0c;\u5b8c\u6210 WebSocket \u63e1\u624b&#xff0c;\u4e4b\u540e\u624d\u80fd\u6536\u53d1&#xff1b;<\/li>\n<li>ws_clients.add(ws)&#xff1a;\u52a0\u5165\u5e7f\u64ad\u96c6\u5408&#xff1b;<\/li>\n<li>\u5185\u90e8 send \u8f85\u52a9\u51fd\u6570&#xff1a;\u628a dict \u5e8f\u5217\u5316\u6210 JSON \u5b57\u7b26\u4e32\u518d\u53d1\u3002\u540e\u9762\u6240\u6709\u547d\u4ee4\u56de\u6267\u90fd\u8c03\u5b83&#xff0c;\u907f\u514d\u91cd\u590d\u5199 json.dumps\u3002<\/li>\n<\/ul>\n<h4>4.3.5 \u63e1\u624b hello<\/h4>\n<p>    <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token comment\"># \u63e1\u624b\u6210\u529f\u540e\u7acb\u5373\u53d1 hello, \u628a\u83dc\u5355\u548c\u5f53\u524d\u5feb\u7167\u7ed9\u5ba2\u6237\u7aef<\/span><br \/>\n        <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>HelloMsg<span class=\"token punctuation\">(<\/span><br \/>\n            <span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;hello&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            menu<span class=\"token operator\">&#061;<\/span><span class=\"token punctuation\">[<\/span>m<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token keyword\">for<\/span> m <span class=\"token keyword\">in<\/span> MENU<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            statuses<span class=\"token operator\">&#061;<\/span>STATUSES<span class=\"token punctuation\">,<\/span><br \/>\n            orders<span class=\"token operator\">&#061;<\/span><span class=\"token builtin\">sorted<\/span><span class=\"token punctuation\">(<\/span>orders<span class=\"token punctuation\">.<\/span>values<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> key<span class=\"token operator\">&#061;<\/span><span class=\"token keyword\">lambda<\/span> o<span class=\"token punctuation\">:<\/span> <span class=\"token operator\">&#8211;<\/span>o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;id&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        <span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u548c SSE \u4e00\u6837&#xff0c;\u8fde\u4e0a\u7acb\u523b\u53d1 hello&#xff0c;\u4f46 WS \u7684 hello \u591a\u5e26\u4e00\u4e2a orders&#xff1a;\u5f53\u524d\u6240\u6709\u8ba2\u5355\u3002\u8fd9\u6837\u524d\u7aef\u4e00\u8fde\u4e0a\u5c31\u80fd\u7acb\u523b\u6e32\u67d3\u64cd\u4f5c\u53f0\u7684\u8ba2\u5355\u5361\u7247&#xff0c;\u4e0d\u7528\u7b49\u4e0b\u4e00\u6b21\u5e7f\u64ad&#xff1b;<\/li>\n<li>sorted(&#8230;, key&#061;lambda o: -o[&#034;id&#034;])&#xff1a;\u6309 id \u5012\u5e8f&#xff0c;\u6700\u65b0\u5728\u524d\u3002<\/li>\n<\/ul>\n<h4>4.3.6 \u547d\u4ee4\u5206\u53d1\u5faa\u73af<\/h4>\n<p>        <span class=\"token comment\"># \u547d\u4ee4\u5206\u53d1<\/span><br \/>\n        <span class=\"token keyword\">while<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            raw <span class=\"token operator\">&#061;<\/span> <span class=\"token keyword\">await<\/span> ws<span class=\"token punctuation\">.<\/span>receive_text<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                msg <span class=\"token operator\">&#061;<\/span> json<span class=\"token punctuation\">.<\/span>loads<span class=\"token punctuation\">(<\/span>raw<span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">except<\/span> json<span class=\"token punctuation\">.<\/span>JSONDecodeError<span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>ErrorMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> error<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;invalid json&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">continue<\/span><\/p>\n<p>            cmd <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>msg<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;cmd&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>lower<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            arg <span class=\"token operator\">&#061;<\/span> msg<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;arg&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>await ws.receive_text()&#xff1a;\u963b\u585e\u7b49\u5f85\u5ba2\u6237\u7aef\u53d1\u6765\u7684\u4e0b\u4e00\u6761\u6587\u672c\u6d88\u606f&#xff1b;<\/li>\n<li>\u524d\u7aef\u53d1\u7684\u683c\u5f0f\u7ea6\u5b9a\u4e3a JSON&#xff1a;{&#034;cmd&#034;: &#034;add&#034;} \u6216 {&#034;cmd&#034;: &#034;pickup&#034;, &#034;arg&#034;: 3}&#xff1b;<\/li>\n<li>json.loads \u89e3\u6790&#xff0c;\u5931\u8d25\u5c31\u56de error: invalid json&#xff0c;continue \u7ee7\u7eed\u7b49\u4e0b\u4e00\u6761&#xff1b;<\/li>\n<li>cmd \u53d6\u5c0f\u5199&#xff1b;arg \u662f\u53ef\u9009\u53c2\u6570&#xff08;pickup \u9700\u8981&#xff09;\u3002<\/li>\n<\/ul>\n<h4>4.3.7 \u56db\u4e2a\u547d\u4ee4\u5206\u652f<\/h4>\n<p>            <span class=\"token keyword\">if<\/span> cmd <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;ping&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>PongMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;pong&#034;<\/span><span class=\"token punctuation\">,<\/span> time<span class=\"token operator\">&#061;<\/span>now_iso<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>ping&#xff1a;\u6700\u7b80\u5355&#xff0c;\u56de pong &#043; \u5f53\u524d\u65f6\u95f4\u3002\u524d\u7aef\u7528\u6765\u6d4b\u5f80\u8fd4\u5ef6\u8fdf\u3002<\/li>\n<\/ul>\n<p>            <span class=\"token keyword\">elif<\/span> cmd <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;add&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                o <span class=\"token operator\">&#061;<\/span> new_order<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                orders<span class=\"token punctuation\">[<\/span>o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;id&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> o<br \/>\n                <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>AddedMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;added&#034;<\/span><span class=\"token punctuation\">,<\/span> order<span class=\"token operator\">&#061;<\/span>o<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>add&#xff1a;\u8c03 new_order() \u751f\u6210\u4e00\u676f\u968f\u673a\u8ba2\u5355&#xff0c;\u5b58\u8fdb orders&#xff0c;\u56de added &#043; \u65b0\u8ba2\u5355\u8be6\u60c5\u3002\u524d\u7aef\u62ff\u5230\u540e\u53ef\u4ee5\u9ad8\u4eae\u663e\u793a\u65b0\u8ba2\u5355\u3002<\/li>\n<\/ul>\n<p>            <span class=\"token keyword\">elif<\/span> cmd <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;pickup&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    oid <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">(<\/span>arg<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">except<\/span> <span class=\"token punctuation\">(<\/span>TypeError<span class=\"token punctuation\">,<\/span> ValueError<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>ErrorMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> error<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;arg must be int order_id&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                    <span class=\"token keyword\">continue<\/span><br \/>\n                o <span class=\"token operator\">&#061;<\/span> orders<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span>oid<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> o<span class=\"token punctuation\">:<\/span><br \/>\n                    <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>ErrorMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> error<span class=\"token operator\">&#061;<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;order <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>oid<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> not found&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">elif<\/span> o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">!&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u5b8c\u6210&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>ErrorMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> error<span class=\"token operator\">&#061;<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;order <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>oid<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> not ready&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    o<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;status&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u5df2\u53d6\u9910&#034;<\/span><br \/>\n                    <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>PickedMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;picked&#034;<\/span><span class=\"token punctuation\">,<\/span> order<span class=\"token operator\">&#061;<\/span>o<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>pickup \u6700\u590d\u6742&#xff0c;\u8981\u5e26 arg&#xff08;\u8ba2\u5355 id&#xff09;&#xff1a;\n<li>\u5148\u628a arg \u8f6c\u6210 int&#xff0c;\u5931\u8d25\u56de\u9519&#xff08;arg must be int order_id&#xff09;&#xff1b;<\/li>\n<li>\u67e5\u8ba2\u5355\u5b58\u4e0d\u5b58\u5728&#xff0c;\u4e0d\u5b58\u5728\u56de\u9519&#xff1b;<\/li>\n<li>\u53ea\u6709 \u5df2\u5b8c\u6210 \u7684\u8ba2\u5355\u80fd\u53d6\u9910&#xff0c;\u5236\u4f5c\u4e2d \u4e0d\u884c&#xff08;\u56de not ready&#xff09;&#xff1b;<\/li>\n<li>\u6ee1\u8db3\u6761\u4ef6\u5c31\u6539\u6210 \u5df2\u53d6\u9910&#xff0c;\u56de picked &#043; \u66f4\u65b0\u540e\u7684\u8ba2\u5355\u3002<\/li>\n<\/li>\n<li>\u8fd9\u79cd\u300c\u6821\u9a8c \u2192 \u64cd\u4f5c \u2192 \u56de\u6267\u300d\u4e09\u6bb5\u5f0f\u662f\u547d\u4ee4\u5904\u7406\u7684\u901a\u7528\u6a21\u5f0f\u3002<\/li>\n<\/ul>\n<p>            <span class=\"token keyword\">elif<\/span> cmd <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;snapshot&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                snap<span class=\"token punctuation\">:<\/span> Snapshot <span class=\"token operator\">&#061;<\/span> snapshot<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>SnapshotMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;snapshot&#034;<\/span><span class=\"token punctuation\">,<\/span> time<span class=\"token operator\">&#061;<\/span>snap<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;time&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> orders<span class=\"token operator\">&#061;<\/span>snap<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;orders&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>snapshot&#xff1a;\u8c03 models.snapshot()&#xff08;\u4e0d\u6539\u53d8\u72b6\u6001&#xff09;\u62ff\u5f53\u524d\u5feb\u7167&#xff0c;\u56de snapshot &#043; \u65f6\u95f4 &#043; \u6240\u6709\u8ba2\u5355\u3002\u524d\u7aef\u60f3\u968f\u65f6\u5237\u65b0\u7528\u3002<\/li>\n<\/ul>\n<p>            <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span>ErrorMsg<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">type<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> error<span class=\"token operator\">&#061;<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;unknown cmd: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>cmd<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u672a\u77e5\u547d\u4ee4&#xff1a;\u56de\u9519\u3002\u8fd9\u5f88\u91cd\u8981\u2014\u2014\u524d\u7aef\u8c03\u8bd5\u65f6\u6253\u9519\u547d\u4ee4\u80fd\u7acb\u523b\u770b\u5230\u53cd\u9988\u3002<\/li>\n<\/ul>\n<h4>4.3.8 \u65ad\u5f00\u5904\u7406<\/h4>\n<p>    <span class=\"token keyword\">except<\/span> WebSocketDisconnect<span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">pass<\/span><br \/>\n    <span class=\"token keyword\">finally<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        ws_clients<span class=\"token punctuation\">.<\/span>discard<span class=\"token punctuation\">(<\/span>ws<span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>WebSocketDisconnect&#xff1a;\u5ba2\u6237\u7aef\u4e3b\u52a8\u5173\u8fde\u63a5\u65f6&#xff0c;receive_text() \u629b\u8fd9\u4e2a\u5f02\u5e38\u3002\u6211\u4eec pass&#xff08;\u4e0d\u5f53\u4f5c\u9519\u8bef&#xff09;&#xff1b;<\/li>\n<li>finally&#xff1a;\u65e0\u8bba\u6b63\u5e38\u9000\u51fa\u8fd8\u662f\u5f02\u5e38&#xff0c;\u90fd\u628a\u81ea\u5df1\u4ece ws_clients \u79fb\u9664\u3002\u548c SSE \u7684 finally discard \u4e00\u6837&#xff0c;\u9632\u5185\u5b58\u6cc4\u6f0f\u2014\u2014\u5426\u5219\u5e7f\u64ad\u5668\u4f1a\u4e00\u76f4\u5f80\u65ad\u5f00\u7684\u8fde\u63a5\u53d1&#xff0c;send_text \u629b\u5f02\u5e38\u8fd8\u5f97\u5904\u7406\u3002<\/li>\n<\/ul>\n<p>\u5bf9\u6bd4 SSE&#xff1a;SSE \u65ad\u5f00\u4f1a\u8ba9 yield \u629b GeneratorExit&#xff1b;WS \u65ad\u5f00\u8ba9 receive_text \u629b WebSocketDisconnect\u3002\u5904\u7406\u4f4d\u7f6e\u4e0d\u540c&#xff0c;\u4f46\u76ee\u7684\u4e00\u6837\u2014\u2014\u6e05\u7406\u8ba2\u9605\u3002<\/p>\n<hr \/>\n<h3>4.4 \u6570\u636e\u6d41\u56de\u987e<\/h3>\n<p>\u6d4f\u89c8\u5668 new WebSocket(&#039;ws:\/\/&#8230;&#039;)<br \/>\n            \u2502 \u63e1\u624b\u5347\u7ea7<br \/>\n            \u25bc<br \/>\nws_orders() \u2192 accept \u2192 \u52a0\u5165 ws_clients \u2192 \u53d1 hello(\u542b\u5f53\u524d\u8ba2\u5355)<br \/>\n            \u2502<br \/>\n            \u2502  \u5faa\u73af await receive_text():<br \/>\n            \u2502     {&#034;cmd&#034;:&#034;ping&#034;}    \u2192 \u56de {&#034;type&#034;:&#034;pong&#034;,&#8230;}<br \/>\n            \u2502     {&#034;cmd&#034;:&#034;add&#034;}     \u2192 new_order &#043; \u56de {&#034;type&#034;:&#034;added&#034;,&#8230;}<br \/>\n            \u2502     {&#034;cmd&#034;:&#034;pickup&#034;,&#034;arg&#034;:3} \u2192 \u6539\u72b6\u6001 &#043; \u56de {&#034;type&#034;:&#034;picked&#034;,&#8230;}<br \/>\n            \u2502     {&#034;cmd&#034;:&#034;snapshot&#034;} \u2192 \u56de {&#034;type&#034;:&#034;snapshot&#034;,&#8230;}<br \/>\n            \u2502     \u975e\u6cd5\/\u672a\u77e5          \u2192 \u56de {&#034;type&#034;:&#034;error&#034;,&#8230;}<br \/>\n            \u2502<br \/>\n&#xff08;\u65ad\u5f00\u65f6&#xff09; WebSocketDisconnect \u2192 finally: ws_clients.discard(ws)<\/p>\n<p>\u6b64\u5916&#xff0c;\u5e7f\u64ad\u5668&#xff08;\u7b2c 5 \u7ae0&#xff09;\u6bcf 0.8s \u4e5f\u4f1a\u904d\u5386 ws_clients \u7ed9\u6bcf\u4e2a\u8fde\u63a5 send_text(payload)\u2014\u2014\u90a3\u662f\u53e6\u4e00\u6761\u63a8\u9001\u7ebf&#xff0c;\u548c\u8fd9\u91cc\u7684\u547d\u4ee4\u56de\u6267\u7ebf\u5e76\u884c\u3002\u6240\u4ee5 WS \u5ba2\u6237\u7aef\u4f1a\u540c\u65f6\u6536\u5230&#xff1a;\u2460 \u81ea\u5df1\u547d\u4ee4\u7684\u56de\u6267&#xff1b;\u2461 \u5e7f\u64ad\u5668\u63a8\u7684\u5168\u91cf\u8ba2\u5355\u66f4\u65b0\u3002<\/p>\n<h3>4.5 SSE vs WS \u5199\u6cd5\u5bf9\u6bd4&#xff08;\u5148\u770b\u4e00\u773c&#xff0c;\u7b2c 9 \u7ae0\u7ec6\u8bb2&#xff09;<\/h3>\n<table>\n<tr>\u7ef4\u5ea6SSE&#xff08;sse.py&#xff09;WebSocket&#xff08;ws.py&#xff09;<\/tr>\n<tbody>\n<tr>\n<td>\u88c5\u9970\u5668<\/td>\n<td>&#064;router.get<\/td>\n<td>&#064;router.websocket<\/td>\n<\/tr>\n<tr>\n<td>\u63e1\u624b<\/td>\n<td>\u65e0\u9700 accept<\/td>\n<td>\u5fc5\u987b await ws.accept()<\/td>\n<\/tr>\n<tr>\n<td>\u53d1\u9001\u65b9\u5f0f<\/td>\n<td>yield&#xff08;\u5f02\u6b65\u751f\u6210\u5668&#xff09;<\/td>\n<td>await ws.send_text(&#8230;)<\/td>\n<\/tr>\n<tr>\n<td>\u63a5\u6536\u65b9\u5f0f<\/td>\n<td>\u4e0d\u80fd\u63a5\u6536<\/td>\n<td>await ws.receive_text()<\/td>\n<\/tr>\n<tr>\n<td>\u5ba2\u6237\u7aef\u96c6\u5408\u5b58\u4ec0\u4e48<\/td>\n<td>Queue&#xff08;\u7f13\u51b2&#xff09;<\/td>\n<td>WebSocket&#xff08;\u76f4\u63a5\u53d1&#xff09;<\/td>\n<\/tr>\n<tr>\n<td>\u65ad\u5f00\u5f02\u5e38<\/td>\n<td>GeneratorExit<\/td>\n<td>WebSocketDisconnect<\/td>\n<\/tr>\n<tr>\n<td>\u6d4f\u89c8\u5668 API<\/td>\n<td>EventSource&#xff08;\u81ea\u52a8\u91cd\u8fde&#xff09;<\/td>\n<td>WebSocket&#xff08;\u624b\u52a8\u91cd\u8fde&#xff09;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>4.6 \u52a8\u624b\u9a8c\u8bc1&#xff08;\u9700\u5199\u5b8c\u7b2c 6 \u7ae0\u5165\u53e3\u540e&#xff09;<\/h3>\n<p>WebSocket \u4e0d\u80fd\u7528 curl \u76f4\u63a5\u6d4b&#xff08;\u9700\u8981 ws \u534f\u8bae\u63e1\u624b&#xff09;\u3002\u5199\u5b8c\u7b2c 6 \u7ae0\u540e&#xff0c;\u6700\u7b80\u5355\u7684\u9a8c\u8bc1\u662f\u7528\u6d4f\u89c8\u5668\u63a7\u5236\u53f0&#xff1a;<\/p>\n<p><span class=\"token comment\">\/\/ \u5728 http:\/\/127.0.0.1:8000\/ \u9875\u9762\u7684 F12 \u63a7\u5236\u53f0\u6267\u884c<\/span><br \/>\n<span class=\"token keyword\">const<\/span> ws <span class=\"token operator\">&#061;<\/span> <span class=\"token keyword\">new<\/span> <span class=\"token class-name\">WebSocket<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;ws:\/\/127.0.0.1:8000\/ws\/orders&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onmessage<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token parameter\">e<\/span> <span class=\"token operator\">&#061;&gt;<\/span> console<span class=\"token punctuation\">.<\/span><span class=\"token function\">log<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">parse<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>data<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onopen<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> ws<span class=\"token punctuation\">.<\/span><span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">cmd<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">&#034;ping&#034;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>   <span class=\"token comment\">\/\/ 2 \u79d2\u540e\u4f1a\u770b\u5230 {type:&#034;pong&#034;}<\/span><br \/>\n<span class=\"token comment\">\/\/ \u7b49 2 \u79d2\u518d\u8bd5:<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">cmd<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">&#034;add&#034;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>                      <span class=\"token comment\">\/\/ \u770b\u5230 {type:&#034;added&#034;, order:{&#8230;}}<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">cmd<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">&#034;snapshot&#034;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>                 <span class=\"token comment\">\/\/ \u770b\u5230 {type:&#034;snapshot&#034;, &#8230;}<\/span><\/p>\n<p>\u6216\u8005\u76f4\u63a5\u7528\u9879\u76ee\u81ea\u5e26\u7684\u9875\u9762&#xff08;\u7b2c 7 \u7ae0&#xff09;&#xff0c;\u70b9\u53f3\u4fa7\u300c&#x1f4e1; ping \/ \u2795 \u52a0\u5355 \/ &#x1f4f8; snapshot\u300d\u6309\u94ae&#xff0c;\u9ed1\u5e95\u65e5\u5fd7\u533a\u4f1a\u663e\u793a\u6536\u53d1\u6d88\u606f\u3002<\/p>\n<hr \/>\n<p>\u4e0b\u4e00\u7ae0 \u2192 05-\u5e7f\u64ad\u5668-broadcaster.md&#xff1a;\u5199\u540e\u53f0\u5fc3\u8df3&#xff0c;\u628a\u6570\u636e\u540c\u65f6\u63a8\u7ed9 SSE \u548c WS \u4e24\u4e2a\u96c6\u5408\u3002<\/p>\n<hr \/>\n<h2>\u7b2c 5 \u7ae0 \u00b7 \u5e7f\u64ad\u5668 broadcaster.py<\/h2>\n<h3>\u672c\u7ae0\u76ee\u6807<\/h3>\n<p>\u5199\u4e00\u4e2a\u540e\u53f0\u534f\u7a0b\u300c\u5e7f\u64ad\u5668\u300d&#xff0c;\u5b83\u662f SSE \u548c WS \u5171\u4eab\u7684\u5fc3\u8df3\u6e90\u3002\u6bcf 0.8 \u79d2&#xff1a;<\/p>\n<li>\u8c03 models.advance() \u63a8\u8fdb\u6240\u6709\u8ba2\u5355&#xff0c;\u62ff\u5230\u5feb\u7167&#xff1b;<\/li>\n<li>\u628a\u5feb\u7167\u5e8f\u5217\u5316\u6210 JSON&#xff1b;<\/li>\n<li>\u540c\u65f6\u5206\u53d1\u7ed9\u6240\u6709 SSE \u5ba2\u6237\u7aef\u7684 Queue \u548c\u6240\u6709 WS \u5ba2\u6237\u7aef\u7684 WebSocket\u3002<\/li>\n<p>\u5b66\u5b8c\u672c\u7ae0\u4f60\u5c06\u7406\u89e3&#xff1a;<\/p>\n<ul>\n<li>\u540e\u53f0\u4efb\u52a1\u4e3a\u4ec0\u4e48\u7528\u534f\u7a0b\u800c\u4e0d\u662f\u7ebf\u7a0b&#xff1b;<\/li>\n<li>asyncio.create_task &#043; task.cancel() \u7684\u751f\u547d\u5468\u671f\u7ba1\u7406&#xff1b;<\/li>\n<li>\u4e3a\u4ec0\u4e48 SSE \u7528 queue.put\u3001WS \u7528 send_text \u4e24\u79cd\u4e0d\u540c\u5206\u53d1\u65b9\u5f0f&#xff1b;<\/li>\n<li>\u600e\u4e48\u505a\u5230\u300c\u4e00\u5904\u63a8\u8fdb&#xff0c;\u4e24\u8def\u5206\u53d1\u300d\u3002<\/li>\n<\/ul>\n<hr \/>\n<h3>5.1 \u4e3a\u4ec0\u4e48\u9700\u8981\u5e7f\u64ad\u5668&#xff1f;<\/h3>\n<p>\u7b2c 3\u30014 \u7ae0\u5404\u81ea\u7ef4\u62a4\u4e86\u8ba2\u9605\u8005\u96c6\u5408&#xff08;sse_clients \/ ws_clients&#xff09;&#xff0c;\u4f46\u5b83\u4eec\u81ea\u5df1\u4e0d\u77e5\u9053\u4f55\u65f6\u8be5\u63a8\u6570\u636e\u3002\u5982\u679c\u8ba9\u6bcf\u4e2a\u8fde\u63a5\u81ea\u5df1\u53bb\u8f6e\u8be2 advance()&#xff0c;\u4f1a\u6709\u4e24\u4e2a\u95ee\u9898&#xff1a;<\/p>\n<li>\u91cd\u590d\u63a8\u8fdb&#xff1a;\u6bcf\u4e2a\u8fde\u63a5\u90fd\u8c03 advance()&#xff0c;\u8ba2\u5355\u8fdb\u5ea6\u4f1a\u6309\u8fde\u63a5\u6570\u500d\u589e&#xff0c;\u72b6\u6001\u5168\u4e71&#xff1b;<\/li>\n<li>\u4e0d\u4e00\u81f4&#xff1a;\u4e0d\u540c\u8fde\u63a5\u62ff\u5230\u4e0d\u540c\u65f6\u523b\u7684\u5feb\u7167&#xff0c;\u770b\u677f\u5404\u4e0d\u76f8\u540c\u3002<\/li>\n<p>\u6b63\u786e\u505a\u6cd5&#xff1a;\u53ea\u6709\u4e00\u4e2a\u65f6\u949f\u2014\u2014\u5e7f\u64ad\u5668\u3002\u5b83\u6bcf 0.8s \u8c03\u4e00\u6b21 advance()&#xff0c;\u628a\u7ed3\u679c\u540c\u65f6\u53d1\u7ed9\u6240\u6709\u8ba2\u9605\u8005\u3002\u6240\u6709\u8fde\u63a5\u770b\u5230\u7684\u662f\u540c\u4e00\u4efd\u6570\u636e\u3001\u540c\u4e00\u65f6\u523b\u7684\u66f4\u65b0\u3002<\/p>\n<h3>5.2 \u539f\u59cb\u5b8c\u6574\u4ee3\u7801<\/h3>\n<p>\u65b0\u5efa\u6587\u4ef6 src\/broadcaster.py&#xff0c;\u5b8c\u6574\u7167\u6284&#xff1a;<\/p>\n<p><span class=\"token triple-quoted-string string\">&#034;&#034;&#034;<br \/>\n\u540e\u53f0\u5e7f\u64ad\u4efb\u52a1: \u6bcf 0.8s \u63a8\u8fdb\u8ba2\u5355\u5e76\u5206\u53d1\u7ed9\u6240\u6709 SSE \/ WS \u5ba2\u6237\u7aef.<\/p>\n<p>\u8fd9\u662f SSE \u4e0e WS \u5171\u4eab\u7684&#034;\u5fc3\u8df3\u6e90&#034;. \u5404\u81ea\u7ef4\u62a4\u81ea\u5df1\u7684\u8ba2\u9605\u8005\u96c6\u5408,<br \/>\n\u5e7f\u64ad\u5668\u53ea\u8d1f\u8d23: \u63a8\u8fdb\u72b6\u6001 -&gt; \u7f16\u7801 JSON -&gt; \u6295\u9012\u5230\u4e24\u4e2a\u96c6\u5408.<br \/>\n&#034;&#034;&#034;<\/span><\/p>\n<p><span class=\"token keyword\">import<\/span> asyncio<br \/>\n<span class=\"token keyword\">import<\/span> json<\/p>\n<p><span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>models <span class=\"token keyword\">import<\/span> advance<br \/>\n<span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>sse <span class=\"token keyword\">import<\/span> sse_clients<br \/>\n<span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>ws <span class=\"token keyword\">import<\/span> ws_clients<\/p>\n<p><span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">broadcaster<\/span><span class=\"token punctuation\">(<\/span>interval<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">float<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token number\">0.8<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> <span class=\"token boolean\">None<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6c38\u4e45\u5faa\u73af: \u63a8\u8fdb\u72b6\u6001\u5e76\u5e7f\u64ad; \u534f\u7a0b\u88ab\u53d6\u6d88\u65f6\u81ea\u52a8\u9000\u51fa.&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token keyword\">while<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        snapshot <span class=\"token operator\">&#061;<\/span> advance<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        payload <span class=\"token operator\">&#061;<\/span> json<span class=\"token punctuation\">.<\/span>dumps<span class=\"token punctuation\">(<\/span>snapshot<span class=\"token punctuation\">,<\/span> ensure_ascii<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># SSE: \u6bcf\u4e2a\u8ba2\u9605\u8005\u4e00\u4efd Queue, \u4e3b\u7ebf\u7a0b\u975e\u963b\u585e\u5730\u585e\u5165\u65b0\u4e8b\u4ef6<\/span><br \/>\n        <span class=\"token keyword\">for<\/span> queue <span class=\"token keyword\">in<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">(<\/span>sse_clients<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">await<\/span> queue<span class=\"token punctuation\">.<\/span>put<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;event&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;orders&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;data&#034;<\/span><span class=\"token punctuation\">:<\/span> payload<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># WS: \u76f4\u63a5 send_text, \u53d1\u9001\u5931\u8d25\u8bf4\u660e\u8fde\u63a5\u5df2\u65ad, \u4ece\u96c6\u5408\u79fb\u9664<\/span><br \/>\n        <span class=\"token keyword\">for<\/span> ws <span class=\"token keyword\">in<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">(<\/span>ws_clients<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">await<\/span> ws<span class=\"token punctuation\">.<\/span>send_text<span class=\"token punctuation\">(<\/span>payload<span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">except<\/span> Exception<span class=\"token punctuation\">:<\/span><br \/>\n                ws_clients<span class=\"token punctuation\">.<\/span>discard<span class=\"token punctuation\">(<\/span>ws<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token keyword\">await<\/span> asyncio<span class=\"token punctuation\">.<\/span>sleep<span class=\"token punctuation\">(<\/span>interval<span class=\"token punctuation\">)<\/span><\/p>\n<hr \/>\n<h3>5.3 \u9010\u6bb5\u8bb2\u89e3<\/h3>\n<h4>5.3.1 \u5bfc\u5165<\/h4>\n<p><span class=\"token keyword\">import<\/span> asyncio<br \/>\n<span class=\"token keyword\">import<\/span> json<\/p>\n<p><span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>models <span class=\"token keyword\">import<\/span> advance<br \/>\n<span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>sse <span class=\"token keyword\">import<\/span> sse_clients<br \/>\n<span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>ws <span class=\"token keyword\">import<\/span> ws_clients<\/p>\n<ul>\n<li>advance&#xff1a;\u6bcf tick \u8c03\u4e00\u6b21&#xff0c;\u63a8\u8fdb\u8ba2\u5355\u72b6\u6001\u5e76\u8fd4\u56de\u5feb\u7167&#xff1b;<\/li>\n<li>sse_clients&#xff1a;\u4ece sse.py \u5bfc\u5165\u7684 Queue \u96c6\u5408&#xff1b;<\/li>\n<li>ws_clients&#xff1a;\u4ece ws.py \u5bfc\u5165\u7684 WebSocket \u96c6\u5408&#xff1b;<\/li>\n<li>\u6ce8\u610f broadcaster.py \u540c\u65f6\u4f9d\u8d56\u4e24\u4e2a\u4f20\u8f93\u6a21\u5757\u2014\u2014\u5b83\u662f\u628a\u4e24\u8005\u4e32\u8d77\u6765\u7684\u300c\u80f6\u6c34\u300d\u3002<\/li>\n<\/ul>\n<h4>5.3.2 \u4e3b\u5faa\u73af<\/h4>\n<p><span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">broadcaster<\/span><span class=\"token punctuation\">(<\/span>interval<span class=\"token punctuation\">:<\/span> <span class=\"token builtin\">float<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token number\">0.8<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> <span class=\"token boolean\">None<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6c38\u4e45\u5faa\u73af: \u63a8\u8fdb\u72b6\u6001\u5e76\u5e7f\u64ad; \u534f\u7a0b\u88ab\u53d6\u6d88\u65f6\u81ea\u52a8\u9000\u51fa.&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token keyword\">while<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        snapshot <span class=\"token operator\">&#061;<\/span> advance<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        payload <span class=\"token operator\">&#061;<\/span> json<span class=\"token punctuation\">.<\/span>dumps<span class=\"token punctuation\">(<\/span>snapshot<span class=\"token punctuation\">,<\/span> ensure_ascii<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>async def&#xff1a;\u534f\u7a0b\u3002\u56e0\u4e3a\u8981 await \u53d1\u9001\u64cd\u4f5c\u548c sleep&#xff1b;<\/li>\n<li>interval&#061;0.8&#xff1a;\u9ed8\u8ba4 0.8 \u79d2\u4e00 tick\u3002\u8c03\u6162\u70b9&#xff08;\u5982 2.0&#xff09;\u80fd\u770b\u5f97\u66f4\u6e05\u695a&#xff0c;\u8c03\u5feb\u70b9&#xff08;\u5982 0.3&#xff09;\u66f4\u523a\u6fc0&#xff1b;<\/li>\n<li>while True&#xff1a;\u6c38\u4e45\u5faa\u73af&#xff0c;\u76f4\u5230\u88ab\u53d6\u6d88&#xff1b;<\/li>\n<li>advance()&#xff1a;\u540c\u6b65\u8c03\u7528&#xff08;\u4e0d\u662f await&#xff09;&#xff0c;\u56e0\u4e3a\u5b83\u64cd\u4f5c\u7684\u662f\u666e\u901a dict&#xff0c;\u6ca1\u6709 IO&#xff1b;<\/li>\n<li>json.dumps(snapshot, ensure_ascii&#061;False)&#xff1a;\u6574\u4e2a\u5feb\u7167\u5e8f\u5217\u5316\u6210\u5b57\u7b26\u4e32&#xff0c;\u7ed9 SSE \u548c WS \u5171\u7528\u4e00\u4efd&#xff08;SSE \u628a\u5b83\u5305\u8fdb data:&#xff0c;WS \u76f4\u63a5\u53d1&#xff09;\u3002<\/li>\n<\/ul>\n<h4>5.3.3 \u5206\u53d1\u7ed9 SSE&#xff1a;queue.put<\/h4>\n<p>        <span class=\"token comment\"># SSE: \u6bcf\u4e2a\u8ba2\u9605\u8005\u4e00\u4efd Queue, \u4e3b\u7ebf\u7a0b\u975e\u963b\u585e\u5730\u585e\u5165\u65b0\u4e8b\u4ef6<\/span><br \/>\n        <span class=\"token keyword\">for<\/span> queue <span class=\"token keyword\">in<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">(<\/span>sse_clients<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">await<\/span> queue<span class=\"token punctuation\">.<\/span>put<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;event&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;orders&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;data&#034;<\/span><span class=\"token punctuation\">:<\/span> payload<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u904d\u5386\u6240\u6709 SSE \u5ba2\u6237\u7aef\u7684 Queue&#xff0c;\u628a {&#034;event&#034;: &#034;orders&#034;, &#034;data&#034;: payload} \u585e\u8fdb\u53bb&#xff1b;<\/li>\n<li>list(sse_clients)&#xff1a;\u5148\u8f6c list \u518d\u904d\u5386\u2014\u2014\u9632\u6b62\u904d\u5386\u8fc7\u7a0b\u4e2d\u96c6\u5408\u88ab\u4fee\u6539&#xff08;\u8fde\u63a5\u65ad\u5f00\u65f6 sse.py \u7684 finally \u4f1a discard&#xff0c;\u6539\u53d8\u96c6\u5408\u5927\u5c0f&#xff0c;\u76f4\u63a5\u904d\u5386 set \u4f1a\u629b RuntimeError: Set changed size during iteration&#xff09;&#xff1b;<\/li>\n<li>await queue.put(&#8230;)&#xff1a;asyncio.Queue \u9ed8\u8ba4\u65e0\u754c&#xff0c;put \u51e0\u4e4e\u4e0d\u963b\u585e&#xff08;\u9664\u975e\u8bbe\u7f6e\u4e86 maxsize&#xff09;\u3002\u6240\u4ee5\u5e7f\u64ad\u5668\u4e0d\u4f1a\u56e0\u4e3a\u67d0\u4e2a SSE \u5ba2\u6237\u7aef\u8bfb\u5f97\u6162\u800c\u88ab\u5361\u4f4f\u2014\u2014\u4e8b\u4ef6\u4f1a\u5728\u90a3\u4e2a\u5ba2\u6237\u7aef\u7684 Queue \u91cc\u79ef\u538b&#xff0c;\u7b49\u5b83\u6162\u6162\u6d88\u8d39\u3002<\/li>\n<\/ul>\n<p>\u8fd9\u5c31\u662f SSE \u7528 Queue \u7684\u6838\u5fc3\u597d\u5904&#xff1a;\u751f\u4ea7\u8005&#xff08;\u5e7f\u64ad\u5668&#xff09;\u548c\u6d88\u8d39\u8005&#xff08;\u8fde\u63a5\u534f\u7a0b&#xff09;\u89e3\u8026&#xff0c;\u4e92\u4e0d\u963b\u585e\u3002<\/p>\n<h4>5.3.4 \u5206\u53d1\u7ed9 WS&#xff1a;send_text &#043; \u5f02\u5e38\u6e05\u7406<\/h4>\n<p>        <span class=\"token comment\"># WS: \u76f4\u63a5 send_text, \u53d1\u9001\u5931\u8d25\u8bf4\u660e\u8fde\u63a5\u5df2\u65ad, \u4ece\u96c6\u5408\u79fb\u9664<\/span><br \/>\n        <span class=\"token keyword\">for<\/span> ws <span class=\"token keyword\">in<\/span> <span class=\"token builtin\">list<\/span><span class=\"token punctuation\">(<\/span>ws_clients<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">await<\/span> ws<span class=\"token punctuation\">.<\/span>send_text<span class=\"token punctuation\">(<\/span>payload<span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">except<\/span> Exception<span class=\"token punctuation\">:<\/span><br \/>\n                ws_clients<span class=\"token punctuation\">.<\/span>discard<span class=\"token punctuation\">(<\/span>ws<span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u904d\u5386\u6240\u6709 WS \u8fde\u63a5&#xff0c;\u76f4\u63a5 await ws.send_text(payload)&#xff1b;<\/li>\n<li>\u540c\u6837 list(ws_clients) \u9632\u904d\u5386\u4e2d\u96c6\u5408\u53d8\u5316&#xff1b;<\/li>\n<li>try\/except&#xff1a;\u5982\u679c\u67d0\u4e2a WS \u5df2\u7ecf\u65ad\u4e86&#xff0c;send_text \u4f1a\u629b\u5f02\u5e38\u3002\u6211\u4eec\u6355\u83b7\u540e\u628a\u5b83\u4ece\u96c6\u5408\u79fb\u9664\u2014\u2014\u8fd9\u6837\u4e0b\u6b21\u5e7f\u64ad\u5c31\u4e0d\u4f1a\u518d\u5c1d\u8bd5\u7ed9\u5b83\u53d1&#xff1b;<\/li>\n<li>\u4e3a\u4ec0\u4e48 SSE \u4e0d\u7528 try\/except&#xff1f;\u56e0\u4e3a SSE \u662f\u5f80 Queue \u91cc\u585e&#xff0c;\u4e0d\u76f4\u63a5\u63a5\u89e6\u8fde\u63a5&#xff0c;\u8fde\u63a5\u65ad\u4e86 Queue \u8fd8\u5728&#xff08;\u76f4\u5230 SSE \u534f\u7a0b\u7684 finally \u6e05\u7406&#xff09;\u3002WS \u662f\u76f4\u63a5\u53d1&#xff0c;\u5fc5\u987b\u5f53\u573a\u5904\u7406\u5931\u8d25\u3002<\/li>\n<\/ul>\n<p>\u4e24\u79cd\u5206\u53d1\u65b9\u5f0f\u7684\u5dee\u5f02&#xff0c;\u672c\u8d28\u662f\u300c\u7f13\u51b2 vs \u76f4\u53d1\u300d&#xff1a;SSE \u6709 Queue \u7f13\u51b2&#xff0c;WS \u65e0\u7f13\u51b2\u76f4\u53d1\u3002\u5404\u6709\u53d6\u820d&#xff1a;SSE \u5bb9\u9519\u597d\u4f46\u65ad\u8fde\u6e05\u7406\u9760\u534f\u7a0b\u81ea\u5df1&#xff1b;WS \u5373\u65f6\u4f46\u5931\u8d25\u8981\u5f53\u573a\u5904\u7406\u3002<\/p>\n<h4>5.3.5 \u8282\u62cd<\/h4>\n<p>        <span class=\"token keyword\">await<\/span> asyncio<span class=\"token punctuation\">.<\/span>sleep<span class=\"token punctuation\">(<\/span>interval<span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u6bcf\u8f6e\u7ed3\u675f\u7761 interval \u79d2&#xff0c;\u63a7\u5236\u5fc3\u8df3\u9891\u7387&#xff1b;<\/li>\n<li>await asyncio.sleep \u4f1a\u8ba9\u51fa\u4e8b\u4ef6\u5faa\u73af&#xff0c;\u8ba9\u5176\u4ed6\u534f\u7a0b&#xff08;\u5404\u8fde\u63a5\u7684\u6536\u53d1&#xff09;\u6709\u673a\u4f1a\u8fd0\u884c&#xff1b;<\/li>\n<li>\u7528 sleep \u800c\u4e0d\u662f time.sleep&#xff1a;time.sleep \u4f1a\u963b\u585e\u6574\u4e2a\u4e8b\u4ef6\u5faa\u73af&#xff0c;\u6240\u6709\u8fde\u63a5\u90fd\u4f1a\u5361\u4f4f\u3002asyncio.sleep \u662f\u534f\u7a0b\u53cb\u597d\u7684\u3002<\/li>\n<\/ul>\n<h3>5.4 \u5e7f\u64ad\u5668\u7684\u4e00\u751f&#xff08;\u751f\u547d\u5468\u671f&#xff09;<\/h3>\n<p>\u5e7f\u64ad\u5668\u4e0d\u662f\u81ea\u5df1\u542f\u52a8\u7684&#xff0c;\u5b83\u7531 app.py \u7684 lifespan \u5728\u5e94\u7528\u542f\u52a8\u65f6\u521b\u5efa&#xff1a;<\/p>\n<p>\u5e94\u7528\u542f\u52a8 (lifespan yield \u4e4b\u524d)<br \/>\n    \u2502<br \/>\n    \u251c\u2500 asyncio.create_task(broadcaster())   \u2190 \u542f\u52a8\u540e\u53f0\u534f\u7a0b<br \/>\n    \u2502       \u2502<br \/>\n    \u2502       \u2514\u2500 while True: advance() &#043; \u5206\u53d1 &#043; sleep  \u2190 \u4e00\u76f4\u8dd1<br \/>\n    \u2502<br \/>\n    \u25bc  (yield: \u5e94\u7528\u8fd0\u884c\u4e2d, \u5904\u7406\u8bf7\u6c42)<br \/>\n    \u2502<br \/>\n\u5e94\u7528\u5173\u95ed (lifespan yield \u4e4b\u540e, finally)<br \/>\n    \u2502<br \/>\n    \u2514\u2500 task.cancel()   \u2190 \u53d6\u6d88\u5e7f\u64ad\u5668\u534f\u7a0b<br \/>\n            \u2502<br \/>\n            \u2514\u2500 broadcaster \u7684 await \u70b9\u629b CancelledError, while True \u9000\u51fa<\/p>\n<p>task.cancel() \u4f1a\u8ba9\u5e7f\u64ad\u5668\u534f\u7a0b\u5728\u4e0b\u4e00\u6b21 await&#xff08;queue.put \/ send_text \/ sleep&#xff09;\u5904\u629b CancelledError&#xff0c;\u4ece\u800c\u8df3\u51fa while True\u3002\u5e7f\u64ad\u5668\u4e0d\u9700\u8981\u81ea\u5df1\u5199 try\/except CancelledError\u2014\u2014\u534f\u7a0b\u88ab\u53d6\u6d88\u662f\u6b63\u5e38\u9000\u51fa\u8def\u5f84\u3002<\/p>\n<h3>5.5 \u6570\u636e\u6d41\u603b\u89c8&#xff08;\u4e09\u4e2a\u6587\u4ef6\u8054\u52a8&#xff09;<\/h3>\n<p>\u6bcf 0.8 \u79d2:<br \/>\n  broadcaster.py<br \/>\n        \u2502<br \/>\n        \u251c\u2500 advance()  \u2192  models.py \u63a8\u8fdb\u8ba2\u5355, \u8fd4\u56de Snapshot<br \/>\n        \u2502<br \/>\n        \u251c\u2500 json.dumps(snapshot) \u2192 payload \u5b57\u7b26\u4e32<br \/>\n        \u2502<br \/>\n        \u251c\u2500 for queue in sse_clients:  queue.put({&#034;event&#034;:&#034;orders&#034;,&#034;data&#034;:payload})<br \/>\n        \u2502       \u2502<br \/>\n        \u2502       \u2514\u2500 sse.py \u5404 event_stream() \u7684 await queue.get() \u53d6\u51fa<br \/>\n        \u2502              \u2192 yield &#034;event: orders\\\\ndata: payload\\\\n\\\\n&#034;  \u2192 \u6d4f\u89c8\u5668<br \/>\n        \u2502<br \/>\n        \u2514\u2500 for ws in ws_clients:  await ws.send_text(payload)<br \/>\n                \u2502<br \/>\n                \u2514\u2500 \u6d4f\u89c8\u5668 ws.onmessage \u6536\u5230 JSON, \u6309 type \u5206\u53d1(\u4f46\u5e7f\u64ad\u6ca1 type,\u524d\u7aef\u5f53 orders \u7528)<\/p>\n<p>\u6ce8\u610f&#xff1a;\u5e7f\u64ad\u5668\u63a8\u7ed9 WS \u7684 payload \u662f\u7eaf\u5feb\u7167 JSON&#xff08;{&#034;time&#034;:&#8230;,&#034;orders&#034;:[&#8230;]}&#xff09;&#xff0c;\u6ca1\u6709 type \u5b57\u6bb5\u3002\u524d\u7aef\u7684 ws.onmessage \u4f1a\u5224\u65ad&#xff1a;\u5982\u679c\u6d88\u606f\u6ca1\u6709 type \u6216\u8005 type \u4e0d\u5728\u5df2\u77e5\u5217\u8868\u91cc&#xff0c;\u5c31\u5f53\u4f5c\u300c\u8ba2\u5355\u66f4\u65b0\u300d\u5904\u7406&#xff08;\u8be6\u89c1\u7b2c 7 \u7ae0\u524d\u7aef&#xff09;\u3002\u8fd9\u662f\u9879\u76ee\u7684\u4e00\u4e2a\u5c0f\u7ea6\u5b9a\u3002<\/p>\n<h3>5.6 \u52a8\u624b\u9a8c\u8bc1&#xff08;\u9700\u5199\u5b8c\u7b2c 6 \u7ae0&#xff09;<\/h3>\n<p>\u5199\u5b8c app.py \u540e\u542f\u52a8\u670d\u52a1&#xff0c;\u4f60\u4f1a\u770b\u5230&#xff1a;<\/p>\n<ul>\n<li>\u6d4f\u89c8\u5668\u770b\u677f\u6bcf 0.8 \u79d2\u5237\u65b0\u4e00\u6b21&#xff08;\u8ba2\u5355\u8fdb\u5ea6\u6761\u5728\u6da8\u3001\u72b6\u6001\u5728\u53d8&#xff09;&#xff1b;<\/li>\n<li>\u7ec8\u7aef\u65e5\u5fd7\u91cc uvicorn \u4f1a\u6301\u7eed\u6253\u5370 INFO: &#8230; \u7684\u8fde\u63a5\u4fe1\u606f&#xff0c;\u4f46\u4e0d\u4f1a\u6709\u5e7f\u64ad\u65e5\u5fd7&#xff08;\u5e7f\u64ad\u5668\u4e0d print&#xff09;&#xff1b;<\/li>\n<li>\u5173\u95ed\u6d4f\u89c8\u5668&#xff0c;SSE\/WS \u534f\u7a0b\u7684 finally \u4f1a\u6e05\u7406 sse_clients\/ws_clients&#xff0c;\u5e7f\u64ad\u5668\u4e0b\u4e00\u8f6e\u904d\u5386\u7684\u96c6\u5408\u5c31\u5c11\u4e86\u4e00\u4e2a\u5143\u7d20&#xff0c;\u4e0d\u4f1a\u62a5\u9519\u3002<\/li>\n<\/ul>\n<h3>5.7 \u5c0f\u7ed3<\/h3>\n<table>\n<tr>\u8981\u70b9\u8bf4\u660e<\/tr>\n<tbody>\n<tr>\n<td>\u89d2\u8272<\/td>\n<td>SSE \u548c WS \u5171\u4eab\u7684\u552f\u4e00\u5fc3\u8df3\u6e90<\/td>\n<\/tr>\n<tr>\n<td>\u5b9e\u73b0<\/td>\n<td>async def &#043; while True &#043; asyncio.sleep<\/td>\n<\/tr>\n<tr>\n<td>\u542f\u505c<\/td>\n<td>app.py \u7684 lifespan \u7528 create_task \/ cancel<\/td>\n<\/tr>\n<tr>\n<td>SSE \u5206\u53d1<\/td>\n<td>await queue.put(&#8230;)&#xff0c;\u7f13\u51b2\u3001\u4e0d\u963b\u585e<\/td>\n<\/tr>\n<tr>\n<td>WS \u5206\u53d1<\/td>\n<td>await ws.send_text(&#8230;)&#xff0c;\u76f4\u53d1\u3001\u5931\u8d25\u5373\u6e05\u7406<\/td>\n<\/tr>\n<tr>\n<td>\u9632\u904d\u5386\u7a81\u53d8<\/td>\n<td>list(sse_clients) \/ list(ws_clients)<\/td>\n<\/tr>\n<tr>\n<td>\u9891\u7387<\/td>\n<td>interval&#061;0.8 \u79d2\/\u6b21<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<hr \/>\n<p>\u4e0b\u4e00\u7ae0 \u2192 06-\u5e94\u7528\u5165\u53e3-app.md&#xff1a;\u5199 app.py&#xff0c;\u628a\u6570\u636e\u5c42\u3001\u4e24\u4e2a\u4f20\u8f93\u6a21\u5757\u3001\u5e7f\u64ad\u5668\u3001\u9759\u6001\u9875\u9762\u7ec4\u88c5\u6210\u4e00\u4e2a\u5b8c\u6574\u7684 FastAPI \u5e94\u7528\u3002<\/p>\n<hr \/>\n<h2>\u7b2c 6 \u7ae0 \u00b7 \u5e94\u7528\u5165\u53e3 app.py<\/h2>\n<h3>\u672c\u7ae0\u76ee\u6807<\/h3>\n<p>\u5199 src\/app.py&#xff0c;\u628a\u524d\u9762\u6240\u6709\u96f6\u4ef6\u7ec4\u88c5\u6210\u4e00\u4e2a\u80fd\u8dd1\u7684 FastAPI \u5e94\u7528\u3002\u5b66\u5b8c\u672c\u7ae0\u4f60\u5c06\u7406\u89e3&#xff1a;<\/p>\n<ul>\n<li>FastAPI \u7684 lifespan&#xff08;\u751f\u547d\u5468\u671f&#xff09;\u673a\u5236&#xff1a;\u542f\u52a8\u65f6\u5e72\u4ec0\u4e48\u3001\u5173\u95ed\u65f6\u5e72\u4ec0\u4e48&#xff1b;<\/li>\n<li>\u600e\u4e48\u7528 asyncio.create_task \u542f\u52a8\u540e\u53f0\u5e7f\u64ad\u5668&#xff0c;\u5173\u95ed\u65f6 cancel \u5b83&#xff1b;<\/li>\n<li>CORS \u4e2d\u95f4\u4ef6\u4e3a\u4ec0\u4e48\u300c\u5168\u5f00\u300d&#xff1b;<\/li>\n<li>\u600e\u4e48\u7528 include_router \u6302\u8f7d\u72ec\u7acb\u6a21\u5757\u7684\u8def\u7531&#xff1b;<\/li>\n<li>\u600e\u4e48\u7528 StaticFiles \u6302\u8f7d\u9759\u6001\u76ee\u5f55\u3001\u7528 FileResponse \u6e32\u67d3\u9996\u9875\u3002<\/li>\n<\/ul>\n<p>\u5199\u5b8c\u8fd9\u4e00\u7ae0&#xff0c;\u540e\u7aef\u5c31\u5b8c\u6574\u4e86&#xff0c;\u53ef\u4ee5\u542f\u52a8\u9a8c\u8bc1\u3002<\/p>\n<hr \/>\n<h3>6.1 \u539f\u59cb\u5b8c\u6574\u4ee3\u7801<\/h3>\n<p>\u65b0\u5efa\u6587\u4ef6 src\/app.py&#xff0c;\u5b8c\u6574\u7167\u6284&#xff1a;<\/p>\n<p><span class=\"token triple-quoted-string string\">&#034;&#034;&#034;fastapi-sse-ws \u5165\u53e3.<\/p>\n<p>&#8211; lifespan: \u542f\u52a8\u540e\u53f0\u5e7f\u64ad\u4efb\u52a1 (broadcaster.py)<br \/>\n&#8211; CORS: \u5168\u5f00<br \/>\n&#8211; \u8def\u7531: \/sse\/orders  (sse.py)<br \/>\n        \/ws\/orders   (ws.py)<br \/>\n        \/            -&gt; static\/index.html<br \/>\n&#034;&#034;&#034;<\/span><\/p>\n<p><span class=\"token keyword\">import<\/span> asyncio<br \/>\n<span class=\"token keyword\">from<\/span> collections<span class=\"token punctuation\">.<\/span>abc <span class=\"token keyword\">import<\/span> AsyncGenerator<br \/>\n<span class=\"token keyword\">from<\/span> contextlib <span class=\"token keyword\">import<\/span> asynccontextmanager<br \/>\n<span class=\"token keyword\">from<\/span> pathlib <span class=\"token keyword\">import<\/span> Path<\/p>\n<p><span class=\"token keyword\">import<\/span> uvicorn<br \/>\n<span class=\"token keyword\">from<\/span> fastapi <span class=\"token keyword\">import<\/span> FastAPI<br \/>\n<span class=\"token keyword\">from<\/span> fastapi<span class=\"token punctuation\">.<\/span>middleware<span class=\"token punctuation\">.<\/span>cors <span class=\"token keyword\">import<\/span> CORSMiddleware<br \/>\n<span class=\"token keyword\">from<\/span> fastapi<span class=\"token punctuation\">.<\/span>responses <span class=\"token keyword\">import<\/span> FileResponse<br \/>\n<span class=\"token keyword\">from<\/span> fastapi<span class=\"token punctuation\">.<\/span>staticfiles <span class=\"token keyword\">import<\/span> StaticFiles<\/p>\n<p><span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span> <span class=\"token keyword\">import<\/span> sse<span class=\"token punctuation\">,<\/span> ws<br \/>\n<span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>broadcaster <span class=\"token keyword\">import<\/span> broadcaster<\/p>\n<p><span class=\"token decorator annotation punctuation\">&#064;asynccontextmanager<\/span><br \/>\n<span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">lifespan<\/span><span class=\"token punctuation\">(<\/span><span class=\"token keyword\">_<\/span><span class=\"token punctuation\">:<\/span> FastAPI<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> AsyncGenerator<span class=\"token punctuation\">[<\/span><span class=\"token boolean\">None<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u542f\u52a8\u540e\u53f0\u5e7f\u64ad\u4efb\u52a1, \u5173\u95ed\u65f6\u81ea\u52a8\u53d6\u6d88.&#034;&#034;&#034;<\/span><br \/>\n    task <span class=\"token operator\">&#061;<\/span> asyncio<span class=\"token punctuation\">.<\/span>create_task<span class=\"token punctuation\">(<\/span>broadcaster<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">yield<\/span><br \/>\n    <span class=\"token keyword\">finally<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        task<span class=\"token punctuation\">.<\/span>cancel<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>app <span class=\"token operator\">&#061;<\/span> FastAPI<span class=\"token punctuation\">(<\/span>title<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;milk-tea-board&#034;<\/span><span class=\"token punctuation\">,<\/span> version<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;0.1.0&#034;<\/span><span class=\"token punctuation\">,<\/span> lifespan<span class=\"token operator\">&#061;<\/span>lifespan<span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token comment\"># CORS \u5168\u5f00<\/span><br \/>\napp<span class=\"token punctuation\">.<\/span>add_middleware<span class=\"token punctuation\">(<\/span><br \/>\n    CORSMiddleware<span class=\"token punctuation\">,<\/span><br \/>\n    allow_origins<span class=\"token operator\">&#061;<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;*&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    allow_methods<span class=\"token operator\">&#061;<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;*&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    allow_headers<span class=\"token operator\">&#061;<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;*&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    allow_credentials<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">,<\/span><br \/>\n<span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token comment\"># \u6302\u8f7d\u72ec\u7acb\u6a21\u5757\u8def\u7531<\/span><br \/>\napp<span class=\"token punctuation\">.<\/span>include_router<span class=\"token punctuation\">(<\/span>sse<span class=\"token punctuation\">.<\/span>router<span class=\"token punctuation\">)<\/span><br \/>\napp<span class=\"token punctuation\">.<\/span>include_router<span class=\"token punctuation\">(<\/span>ws<span class=\"token punctuation\">.<\/span>router<span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token comment\"># \u9759\u6001\u9875\u9762 (\u4f4d\u4e8e\u9879\u76ee\u6839 static\/)<\/span><br \/>\nSTATIC_DIR <span class=\"token operator\">&#061;<\/span> Path<span class=\"token punctuation\">(<\/span>__file__<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>parent<span class=\"token punctuation\">.<\/span>parent <span class=\"token operator\">\/<\/span> <span class=\"token string\">&#034;static&#034;<\/span><br \/>\napp<span class=\"token punctuation\">.<\/span>mount<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\/static&#034;<\/span><span class=\"token punctuation\">,<\/span> StaticFiles<span class=\"token punctuation\">(<\/span>directory<span class=\"token operator\">&#061;<\/span>STATIC_DIR<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> name<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;static&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token decorator annotation punctuation\">&#064;app<span class=\"token punctuation\">.<\/span>get<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\/&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n<span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">index<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> FileResponse<span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u9996\u9875: \u6e32\u67d3 static\/index.html.&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token keyword\">return<\/span> FileResponse<span class=\"token punctuation\">(<\/span>STATIC_DIR <span class=\"token operator\">\/<\/span> <span class=\"token string\">&#034;index.html&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token keyword\">if<\/span> __name__ <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;__main__&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    uvicorn<span class=\"token punctuation\">.<\/span>run<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;src.app:app&#034;<\/span><span class=\"token punctuation\">,<\/span> host<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;127.0.0.1&#034;<\/span><span class=\"token punctuation\">,<\/span> port<span class=\"token operator\">&#061;<\/span><span class=\"token number\">8000<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">reload<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<hr \/>\n<h3>6.2 \u9010\u6bb5\u8bb2\u89e3<\/h3>\n<h4>6.2.1 \u5bfc\u5165<\/h4>\n<p><span class=\"token keyword\">import<\/span> asyncio<br \/>\n<span class=\"token keyword\">from<\/span> collections<span class=\"token punctuation\">.<\/span>abc <span class=\"token keyword\">import<\/span> AsyncGenerator<br \/>\n<span class=\"token keyword\">from<\/span> contextlib <span class=\"token keyword\">import<\/span> asynccontextmanager<br \/>\n<span class=\"token keyword\">from<\/span> pathlib <span class=\"token keyword\">import<\/span> Path<\/p>\n<p><span class=\"token keyword\">import<\/span> uvicorn<br \/>\n<span class=\"token keyword\">from<\/span> fastapi <span class=\"token keyword\">import<\/span> FastAPI<br \/>\n<span class=\"token keyword\">from<\/span> fastapi<span class=\"token punctuation\">.<\/span>middleware<span class=\"token punctuation\">.<\/span>cors <span class=\"token keyword\">import<\/span> CORSMiddleware<br \/>\n<span class=\"token keyword\">from<\/span> fastapi<span class=\"token punctuation\">.<\/span>responses <span class=\"token keyword\">import<\/span> FileResponse<br \/>\n<span class=\"token keyword\">from<\/span> fastapi<span class=\"token punctuation\">.<\/span>staticfiles <span class=\"token keyword\">import<\/span> StaticFiles<\/p>\n<p><span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span> <span class=\"token keyword\">import<\/span> sse<span class=\"token punctuation\">,<\/span> ws<br \/>\n<span class=\"token keyword\">from<\/span> <span class=\"token punctuation\">.<\/span>broadcaster <span class=\"token keyword\">import<\/span> broadcaster<\/p>\n<ul>\n<li>asyncio&#xff1a;\u542f\u52a8\u540e\u53f0\u4efb\u52a1\u7528&#xff1b;<\/li>\n<li>AsyncGenerator \/ asynccontextmanager&#xff1a;\u7ed9 lifespan \u6807\u6ce8\u7c7b\u578b\u548c\u88c5\u9970\u6210\u5f02\u6b65\u4e0a\u4e0b\u6587\u7ba1\u7406\u5668&#xff08;\u4e0b\u9762\u8be6\u8ff0&#xff09;&#xff1b;<\/li>\n<li>Path&#xff1a;\u8de8\u5e73\u53f0\u62fc\u9759\u6001\u76ee\u5f55\u8def\u5f84&#xff1b;<\/li>\n<li>uvicorn&#xff1a;\u5e95\u90e8 if __name__ \u7528\u5b83\u76f4\u63a5\u542f\u52a8&#xff1b;<\/li>\n<li>FastAPI \/ CORSMiddleware \/ FileResponse \/ StaticFiles&#xff1a;FastAPI \u6838\u5fc3\u7ec4\u4ef6&#xff1b;<\/li>\n<li>from . import sse, ws&#xff1a;\u5bfc\u5165\u4e24\u4e2a\u4f20\u8f93\u6a21\u5757&#xff08;\u7528\u5230\u5b83\u4eec\u7684 router&#xff09;&#xff1b;<\/li>\n<li>from .broadcaster import broadcaster&#xff1a;\u5bfc\u5165\u5e7f\u64ad\u5668\u534f\u7a0b\u3002<\/li>\n<\/ul>\n<h4>6.2.2 lifespan&#xff1a;\u751f\u547d\u5468\u671f\u7ba1\u7406<\/h4>\n<p><span class=\"token decorator annotation punctuation\">&#064;asynccontextmanager<\/span><br \/>\n<span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">lifespan<\/span><span class=\"token punctuation\">(<\/span><span class=\"token keyword\">_<\/span><span class=\"token punctuation\">:<\/span> FastAPI<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> AsyncGenerator<span class=\"token punctuation\">[<\/span><span class=\"token boolean\">None<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u542f\u52a8\u540e\u53f0\u5e7f\u64ad\u4efb\u52a1, \u5173\u95ed\u65f6\u81ea\u52a8\u53d6\u6d88.&#034;&#034;&#034;<\/span><br \/>\n    task <span class=\"token operator\">&#061;<\/span> asyncio<span class=\"token punctuation\">.<\/span>create_task<span class=\"token punctuation\">(<\/span>broadcaster<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">yield<\/span><br \/>\n    <span class=\"token keyword\">finally<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        task<span class=\"token punctuation\">.<\/span>cancel<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>\u8fd9\u662f\u672c\u7ae0\u6700\u5173\u952e\u7684\u4e00\u6bb5&#xff0c;\u6162\u6162\u770b&#xff1a;<\/p>\n<ul>\n<li>lifespan \u662f\u4ec0\u4e48&#xff1a;FastAPI&#xff08;\u5e95\u5c42 Starlette&#xff09;\u63d0\u4f9b\u7684\u4e00\u4e2a\u94a9\u5b50&#xff0c;\u8ba9\u4f60\u5728\u5e94\u7528\u542f\u52a8\u524d\u548c\u5173\u95ed\u540e\u5404\u6267\u884c\u4e00\u6bb5\u4ee3\u7801\u3002\u5b83\u662f\u4e00\u4e2a\u5f02\u6b65\u4e0a\u4e0b\u6587\u7ba1\u7406\u5668&#xff1b;<\/li>\n<li>&#064;asynccontextmanager&#xff1a;\u628a\u4e00\u4e2a\u5e26 yield \u7684 async def \u53d8\u6210\u5f02\u6b65\u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\u3002yield \u4e4b\u524d &#061; \u542f\u52a8\u903b\u8f91&#xff0c;yield \u4e4b\u540e &#061; \u5173\u95ed\u903b\u8f91&#xff1b;<\/li>\n<li>yield \u4e4b\u524d&#xff08;\u542f\u52a8&#xff09;&#xff1a;asyncio.create_task(broadcaster()) \u628a\u5e7f\u64ad\u5668\u534f\u7a0b\u8c03\u5ea6\u5230\u540e\u53f0\u8fd0\u884c&#xff0c;\u7acb\u523b\u8fd4\u56de\u4e00\u4e2a Task \u5bf9\u8c61\u3002\u6b64\u65f6\u5e7f\u64ad\u5668\u5df2\u7ecf\u5f00\u59cb while True \u5faa\u73af\u4e86&#xff1b;<\/li>\n<li>yield&#xff1a;\u628a\u63a7\u5236\u6743\u4ea4\u8fd8\u7ed9 FastAPI&#xff0c;\u5e94\u7528\u5f00\u59cb\u63a5\u6536\u8bf7\u6c42\u3002\u5e7f\u64ad\u5668\u5728\u540e\u53f0\u6301\u7eed\u8dd1&#xff1b;<\/li>\n<li>finally&#xff08;\u5173\u95ed&#xff09;&#xff1a;\u5e94\u7528\u6536\u5230\u5173\u95ed\u4fe1\u53f7&#xff08;Ctrl&#043;C \/ \u505c\u6b62&#xff09;\u65f6&#xff0c;yield \u4e4b\u540e\u6267\u884c\u3002task.cancel() \u53d6\u6d88\u5e7f\u64ad\u5668\u534f\u7a0b&#xff0c;\u5b83\u4f1a\u5728\u4e0b\u4e00\u4e2a await \u70b9\u629b CancelledError \u800c\u9000\u51fa&#xff0c;\u4e0d\u4f1a\u6cc4\u6f0f\u3002<\/li>\n<\/ul>\n<p>_ \u53c2\u6570&#xff1a;lifespan \u51fd\u6570\u7b7e\u540d\u8981\u6c42\u63a5\u6536 FastAPI \u5b9e\u4f8b&#xff0c;\u4f46\u8fd9\u91cc\u7528\u4e0d\u5230&#xff0c;\u6309\u60ef\u4f8b\u547d\u540d _\u3002<\/p>\n<ul>\n<li>\u8fd4\u56de\u7c7b\u578b AsyncGenerator[None]&#xff1a;asynccontextmanager \u88c5\u9970\u540e\u7684\u51fd\u6570\u5b9e\u9645\u8fd4\u56de\u5f02\u6b65\u751f\u6210\u5668&#xff0c;None \u8868\u793a yield \u51fa\u53bb\u7684\u503c\u4e0d\u88ab\u4f7f\u7528\u3002<\/li>\n<\/ul>\n<h4>6.2.3 \u521b\u5efa app &#043; \u7ed1\u5b9a lifespan<\/h4>\n<p>app <span class=\"token operator\">&#061;<\/span> FastAPI<span class=\"token punctuation\">(<\/span>title<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;milk-tea-board&#034;<\/span><span class=\"token punctuation\">,<\/span> version<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;0.1.0&#034;<\/span><span class=\"token punctuation\">,<\/span> lifespan<span class=\"token operator\">&#061;<\/span>lifespan<span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>FastAPI(&#8230;)&#xff1a;\u521b\u5efa\u5e94\u7528\u5b9e\u4f8b&#xff1b;<\/li>\n<li>title \/ version&#xff1a;\u4f1a\u663e\u793a\u5728\u81ea\u52a8\u751f\u6210\u7684 \/docs&#xff08;Swagger UI&#xff09;\u9875\u9762&#xff1b;<\/li>\n<li>lifespan&#061;lifespan&#xff1a;\u628a\u4e0a\u9762\u5b9a\u4e49\u7684 lifespan \u94a9\u5b50\u7ed1\u4e0a\u3002FastAPI \u4f1a\u5728\u542f\u52a8\/\u5173\u95ed\u65f6\u81ea\u52a8\u8c03\u7528\u5b83\u3002<\/li>\n<\/ul>\n<h4>6.2.4 CORS \u4e2d\u95f4\u4ef6&#xff08;\u5168\u5f00&#xff09;<\/h4>\n<p><span class=\"token comment\"># CORS \u5168\u5f00<\/span><br \/>\napp<span class=\"token punctuation\">.<\/span>add_middleware<span class=\"token punctuation\">(<\/span><br \/>\n    CORSMiddleware<span class=\"token punctuation\">,<\/span><br \/>\n    allow_origins<span class=\"token operator\">&#061;<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;*&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    allow_methods<span class=\"token operator\">&#061;<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;*&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    allow_headers<span class=\"token operator\">&#061;<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;*&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span><br \/>\n    allow_credentials<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">,<\/span><br \/>\n<span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>CORS&#xff08;\u8de8\u57df\u8d44\u6e90\u5171\u4eab&#xff09;&#xff1a;\u6d4f\u89c8\u5668\u6709\u540c\u6e90\u7b56\u7565&#xff0c;\u9ed8\u8ba4\u7981\u6b62\u8de8\u57df\u8bf7\u6c42\u3002\u5982\u679c\u524d\u7aef\u4e0d\u5728 127.0.0.1:8000 \u800c\u5728\u522b\u5904&#xff08;\u5982 localhost:5173 \u8dd1 Vue\/React \u5f00\u53d1\u670d\u52a1\u5668&#xff09;&#xff0c;\u5c31\u9700\u8981\u670d\u52a1\u5668\u5141\u8bb8\u8de8\u57df&#xff1b;<\/li>\n<li>\u8fd9\u91cc\u5168\u5f00&#xff08;\u6559\u5b66\u9879\u76ee&#xff09;&#xff1a;\n<ul>\n<li>allow_origins&#061;[&#034;*&#034;]&#xff1a;\u5141\u8bb8\u4efb\u4f55\u6765\u6e90&#xff1b;<\/li>\n<li>allow_methods&#061;[&#034;*&#034;]&#xff1a;\u5141\u8bb8\u4efb\u4f55 HTTP \u65b9\u6cd5&#xff1b;<\/li>\n<li>allow_headers&#061;[&#034;*&#034;]&#xff1a;\u5141\u8bb8\u4efb\u4f55\u8bf7\u6c42\u5934&#xff1b;<\/li>\n<li>allow_credentials&#061;True&#xff1a;\u5141\u8bb8\u5e26 cookie&#xff08;\u672c\u9879\u76ee\u5176\u5b9e\u7528\u4e0d\u5230&#xff0c;\u4fdd\u7559&#xff09;&#xff1b;<\/li>\n<\/ul>\n<\/li>\n<li>\u751f\u4ea7\u73af\u5883\u4e0d\u8981\u8fd9\u6837\u5168\u5f00&#xff0c;\u8981\u7cbe\u786e\u6307\u5b9a\u5141\u8bb8\u7684\u6e90\u3002<\/li>\n<\/ul>\n<p>\u6ce8\u610f&#xff1a;allow_origins&#061;[&#034;*&#034;] &#043; allow_credentials&#061;True \u5728\u4e25\u683c\u6d4f\u89c8\u5668\u91cc\u5176\u5b9e\u6709\u51b2\u7a81&#xff08;CORS \u89c4\u8303\u4e0d\u5141\u8bb8 * \u914d\u5408 credentials&#xff09;&#xff0c;\u4f46 FastAPI \u7684 CORS \u4e2d\u95f4\u4ef6\u4f1a\u81ea\u52a8\u5904\u7406&#xff0c;\u6559\u5b66\u573a\u666f\u6ca1\u95ee\u9898\u3002<\/p>\n<h4>6.2.5 \u6302\u8f7d\u8def\u7531<\/h4>\n<p><span class=\"token comment\"># \u6302\u8f7d\u72ec\u7acb\u6a21\u5757\u8def\u7531<\/span><br \/>\napp<span class=\"token punctuation\">.<\/span>include_router<span class=\"token punctuation\">(<\/span>sse<span class=\"token punctuation\">.<\/span>router<span class=\"token punctuation\">)<\/span><br \/>\napp<span class=\"token punctuation\">.<\/span>include_router<span class=\"token punctuation\">(<\/span>ws<span class=\"token punctuation\">.<\/span>router<span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>include_router&#xff1a;\u628a sse.py \u548c ws.py \u91cc APIRouter \u4e0a\u5b9a\u4e49\u7684\u8def\u7531&#xff08;\/sse\/orders\u3001\/ws\/orders&#xff09;\u6ce8\u518c\u5230\u4e3b app&#xff1b;<\/li>\n<li>\u8fd9\u6837\u6bcf\u4e2a\u6a21\u5757\u81ea\u5df1\u7ba1\u81ea\u5df1\u7684\u8def\u7531&#xff0c;app.py \u53ea\u8d1f\u8d23\u7ec4\u88c5&#xff0c;\u804c\u8d23\u6e05\u6670&#xff1b;<\/li>\n<li>\u5982\u679c\u540e\u9762\u8981\u52a0\u65b0\u6a21\u5757&#xff08;\u5982 \/api\/v2\/&#8230;&#xff09;&#xff0c;\u518d\u5199\u4e00\u4e2a xxx.py \u5b9a\u4e49 router&#xff0c;\u8fd9\u91cc include_router \u5373\u53ef\u3002<\/li>\n<\/ul>\n<h4>6.2.6 \u9759\u6001\u8d44\u6e90\u6302\u8f7d<\/h4>\n<p><span class=\"token comment\"># \u9759\u6001\u9875\u9762 (\u4f4d\u4e8e\u9879\u76ee\u6839 static\/)<\/span><br \/>\nSTATIC_DIR <span class=\"token operator\">&#061;<\/span> Path<span class=\"token punctuation\">(<\/span>__file__<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>parent<span class=\"token punctuation\">.<\/span>parent <span class=\"token operator\">\/<\/span> <span class=\"token string\">&#034;static&#034;<\/span><br \/>\napp<span class=\"token punctuation\">.<\/span>mount<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\/static&#034;<\/span><span class=\"token punctuation\">,<\/span> StaticFiles<span class=\"token punctuation\">(<\/span>directory<span class=\"token operator\">&#061;<\/span>STATIC_DIR<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> name<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;static&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>Path(__file__)&#xff1a;app.py \u81ea\u5df1\u7684\u8def\u5f84&#xff0c;\u5373 src\/app.py&#xff1b;<\/li>\n<li>.parent.parent&#xff1a;\u4e0a\u4e00\u7ea7\u4e0a\u4e00\u7ea7 &#061; \u9879\u76ee\u6839\u76ee\u5f55&#xff1b;<\/li>\n<li>\/ &#034;static&#034;&#xff1a;\u62fc\u51fa \u9879\u76ee\u6839\/static&#xff0c;\u8de8\u5e73\u53f0&#xff08;Windows \u7528 \\\\ \u4e5f\u80fd\u6b63\u786e\u5904\u7406&#xff09;&#xff1b;<\/li>\n<li>app.mount(&#034;\/static&#034;, StaticFiles(directory&#061;STATIC_DIR), &#8230;)&#xff1a;\u628a static\/ \u76ee\u5f55\u6302\u5230 \/static\/ URL \u8def\u5f84\u4e0b\u3002\u6d4f\u89c8\u5668\u8bbf\u95ee \/static\/index.html \u5c31\u80fd\u62ff\u5230\u6587\u4ef6\u3002\u524d\u7aef\u9875\u9762\u91cc\u5982\u679c\u6709 &lt;img src&#061;&#034;\/static\/x.png&#034;&gt; \u5c31\u4f1a\u4ece\u8fd9\u91cc\u627e&#xff1b;<\/li>\n<li>name&#061;&#034;static&#034;&#xff1a;\u7ed9\u8fd9\u4e2a\u6302\u8f7d\u70b9\u8d77\u4e2a\u540d&#xff0c;\u65b9\u4fbf\u53cd\u5411\u5f15\u7528\u3002<\/li>\n<\/ul>\n<h4>6.2.7 \u9996\u9875\u8def\u7531<\/h4>\n<p><span class=\"token decorator annotation punctuation\">&#064;app<span class=\"token punctuation\">.<\/span>get<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\/&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n<span class=\"token keyword\">async<\/span> <span class=\"token keyword\">def<\/span> <span class=\"token function\">index<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token operator\">&gt;<\/span> FileResponse<span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u9996\u9875: \u6e32\u67d3 static\/index.html.&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token keyword\">return<\/span> FileResponse<span class=\"token punctuation\">(<\/span>STATIC_DIR <span class=\"token operator\">\/<\/span> <span class=\"token string\">&#034;index.html&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u8bbf\u95ee\u6839\u8def\u5f84 \/ \u65f6&#xff0c;\u8fd4\u56de static\/index.html \u6587\u4ef6&#xff1b;<\/li>\n<li>FileResponse&#xff1a;\u628a\u78c1\u76d8\u6587\u4ef6\u4f5c\u4e3a\u54cd\u5e94\u4f53\u8fd4\u56de&#xff0c;\u81ea\u52a8\u8bbe\u7f6e Content-Type&#xff08;html \u6587\u4ef6\u4f1a\u8bbe\u6210 text\/html&#xff09;&#xff1b;<\/li>\n<li>\u8fd9\u6837\u7528\u6237\u8bbf\u95ee http:\/\/127.0.0.1:8000\/ \u76f4\u63a5\u770b\u5230\u770b\u677f\u9875\u9762&#xff08;\u7b2c 7 \u7ae0\u5199&#xff09;\u3002<\/li>\n<\/ul>\n<h4>6.2.8 \u76f4\u63a5\u8fd0\u884c\u5165\u53e3<\/h4>\n<p><span class=\"token keyword\">if<\/span> __name__ <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;__main__&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    uvicorn<span class=\"token punctuation\">.<\/span>run<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;src.app:app&#034;<\/span><span class=\"token punctuation\">,<\/span> host<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;127.0.0.1&#034;<\/span><span class=\"token punctuation\">,<\/span> port<span class=\"token operator\">&#061;<\/span><span class=\"token number\">8000<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">reload<\/span><span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>if __name__ &#061;&#061; &#034;__main__&#034;&#xff1a;\u53ea\u6709\u76f4\u63a5 python src\/app.py \u8fd0\u884c\u65f6\u624d\u6267\u884c&#xff0c;\u88ab import \u65f6\u4e0d\u6267\u884c&#xff1b;<\/li>\n<li>uvicorn.run(&#034;src.app:app&#034;, &#8230;)&#xff1a;\u7528 uvicorn \u542f\u52a8\u5e94\u7528\u3002\u6ce8\u610f\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u5b57\u7b26\u4e32 &#034;src.app:app&#034;&#xff08;\u6a21\u5757\u8def\u5f84:\u53d8\u91cf\u540d&#xff09;&#xff0c;\u4e0d\u662f app \u5bf9\u8c61\u672c\u8eab\u2014\u2014\u56e0\u4e3a reload&#061;True \u9700\u8981\u91cd\u65b0\u5bfc\u5165\u6a21\u5757&#xff0c;\u5fc5\u987b\u7528\u5b57\u7b26\u4e32&#xff1b;<\/li>\n<li>host&#061;&#034;127.0.0.1&#034;&#xff1a;\u53ea\u76d1\u542c\u672c\u673a&#xff08;\u5f00\u53d1\u7528&#xff09;\u3002\u8981\u5916\u7f51\u8bbf\u95ee\u6539\u6210 0.0.0.0&#xff1b;<\/li>\n<li>port&#061;8000&#xff1a;\u7aef\u53e3&#xff1b;<\/li>\n<li>reload&#061;True&#xff1a;\u4ee3\u7801\u6539\u52a8\u81ea\u52a8\u91cd\u542f&#xff0c;\u5f00\u53d1\u795e\u5668\u3002\u751f\u4ea7\u73af\u5883\u8981\u5173\u6389\u3002<\/li>\n<\/ul>\n<p>\u4e5f\u53ef\u4ee5\u4e0d\u7528\u8fd9\u4e2a if&#xff0c;\u76f4\u63a5\u547d\u4ee4\u884c&#xff1a;uv run python -m uvicorn src.app:app &#8211;reload&#xff0c;\u6548\u679c\u4e00\u6837\u3002\u7b2c 8 \u7ae0\u63a8\u8350\u7528\u547d\u4ee4\u884c\u65b9\u5f0f\u3002<\/p>\n<hr \/>\n<h3>6.3 \u5e94\u7528\u7684\u7ec4\u88c5\u5168\u666f<\/h3>\n<p>src\/app.py<br \/>\n    \u2502<br \/>\n    \u251c\u2500\u2500 lifespan \u2500\u2500 create_task(broadcaster())  \u2192  \u540e\u53f0\u8dd1<br \/>\n    \u2502                                          \u2192  task.cancel() \u5173\u95ed<br \/>\n    \u2502<br \/>\n    \u251c\u2500\u2500 app &#061; FastAPI(lifespan&#061;lifespan)<br \/>\n    \u2502<br \/>\n    \u251c\u2500\u2500 add_middleware(CORSMiddleware, &#8230;)     \u2190 \u5141\u8bb8\u8de8\u57df<br \/>\n    \u2502<br \/>\n    \u251c\u2500\u2500 include_router(sse.router)              \u2190 \u6302 \/sse\/orders<br \/>\n    \u251c\u2500\u2500 include_router(ws.router)               \u2190 \u6302 \/ws\/orders<br \/>\n    \u2502<br \/>\n    \u251c\u2500\u2500 mount(&#034;\/static&#034;, StaticFiles(&#8230;))      \u2190 \u6302\u9759\u6001\u8d44\u6e90<br \/>\n    \u2502<br \/>\n    \u2514\u2500\u2500 GET &#034;\/&#034; \u2192 FileResponse(index.html)      \u2190 \u9996\u9875<\/p>\n<h3>6.4 \u542f\u52a8\u987a\u5e8f<\/h3>\n<p>python -m uvicorn src.app:app &#8211;reload<br \/>\n        \u2502<br \/>\n        \u251c\u2500 \u5bfc\u5165 src.app \u6a21\u5757 \u2192 \u521b\u5efa app, \u6ce8\u518c\u6240\u6709\u8def\u7531<br \/>\n        \u2502<br \/>\n        \u251c\u2500 uvicorn \u8c03\u7528 lifespan \u8fdb\u5165\u542f\u52a8\u9636\u6bb5:<br \/>\n        \u2502       \u2514\u2500 create_task(broadcaster())  \u2190 \u5e7f\u64ad\u5668\u5f00\u59cb\u540e\u53f0\u8fd0\u884c<br \/>\n        \u2502<br \/>\n        \u251c\u2500 lifespan yield \u2192 \u5e94\u7528\u8fdb\u5165\u300c\u8fd0\u884c\u4e2d\u300d, \u5f00\u59cb\u63a5\u6536\u8bf7\u6c42<br \/>\n        \u2502       \u2502<br \/>\n        \u2502       \u251c\u2500 GET \/sse\/orders  \u2192 sse_orders() \u5efa\u957f\u8fde\u63a5<br \/>\n        \u2502       \u251c\u2500 WS  \/ws\/orders  \u2192 ws_orders() \u5efa\u957f\u8fde\u63a5<br \/>\n        \u2502       \u251c\u2500 GET \/           \u2192 \u8fd4\u56de index.html<br \/>\n        \u2502       \u2514\u2500 (\u5e7f\u64ad\u5668\u6bcf 0.8s \u63a8\u6570\u636e\u7ed9\u6240\u6709\u8fde\u63a5)<br \/>\n        \u2502<br \/>\n        \u2514\u2500 Ctrl&#043;C \u2192 lifespan finally \u2192 task.cancel() \u2192 \u5e7f\u64ad\u5668\u9000\u51fa \u2192 \u5e94\u7528\u5173\u95ed<\/p>\n<h3>6.5 \u52a8\u624b\u9a8c\u8bc1<\/h3>\n<p>\u73b0\u5728\u540e\u7aef\u5df2\u7ecf\u5b8c\u6574&#xff08;\u4f46\u524d\u7aef static\/index.html \u8fd8\u6ca1\u5199&#xff0c;\u7b2c 7 \u7ae0\u5199&#xff09;\u3002\u5148\u9a8c\u8bc1\u540e\u7aef\u80fd\u542f\u52a8&#xff1a;<\/p>\n<p><span class=\"token comment\"># \u5728\u9879\u76ee\u6839\u76ee\u5f55<\/span><br \/>\nuv run python <span class=\"token parameter variable\">-m<\/span> uvicorn src.app:app <span class=\"token parameter variable\">&#8211;host<\/span> <span class=\"token number\">127.0<\/span>.0.1 <span class=\"token parameter variable\">&#8211;port<\/span> <span class=\"token number\">8000<\/span> <span class=\"token parameter variable\">&#8211;reload<\/span><\/p>\n<p>\u671f\u671b\u770b\u5230&#xff1a;<\/p>\n<p>INFO:     Uvicorn running on http:\/\/127.0.0.1:8000 (Press CTRL&#043;C to quit)<br \/>\nINFO:     Started reloader process [xxxx] using StatReload<br \/>\nINFO:     Started server process [xxxx]<br \/>\nINFO:     Waiting for application startup.<br \/>\nINFO:     Application startup complete.<\/p>\n<p>Application startup complete. \u8bf4\u660e lifespan \u7684\u542f\u52a8\u9636\u6bb5\u8dd1\u5b8c\u4e86&#xff0c;\u5e7f\u64ad\u5668\u5df2\u7ecf\u5728\u540e\u53f0\u8fd0\u884c\u3002<\/p>\n<p>\u53e6\u5f00\u4e00\u4e2a\u7ec8\u7aef\u6d4b\u8bd5 SSE&#xff1a;<\/p>\n<p><span class=\"token function\">curl<\/span> <span class=\"token parameter variable\">-N<\/span> http:\/\/127.0.0.1:8000\/sse\/orders<\/p>\n<p>\u5e94\u8be5\u6301\u7eed\u6536\u5230 event: hello \u548c event: orders \u5e27&#xff08;\u6309 Ctrl&#043;C \u9000\u51fa&#xff09;\u3002<\/p>\n<p>\u6d4b\u8bd5\u6839\u8def\u5f84&#xff1a;<\/p>\n<p><span class=\"token function\">curl<\/span> <span class=\"token parameter variable\">-s<\/span> http:\/\/127.0.0.1:8000\/<\/p>\n<p>\u6b64\u65f6\u4f1a\u62a5 404&#xff08;\u56e0\u4e3a static\/index.html \u8fd8\u6ca1\u5199&#xff09;\u3002\u7b2c 7 \u7ae0\u5199\u5b8c\u524d\u7aef\u540e&#xff0c;\u8fd9\u91cc\u4f1a\u8fd4\u56de HTML \u9875\u9762\u3002<\/p>\n<hr \/>\n<p>\u4e0b\u4e00\u7ae0 \u2192 07-\u524d\u7aef\u770b\u677f-index.md&#xff1a;\u5199 static\/index.html&#xff0c;\u628a SSE \u548c WS \u7684\u6570\u636e\u6e32\u67d3\u6210\u5b9e\u65f6\u770b\u677f\u3002<\/p>\n<hr \/>\n<h2>\u7b2c 7 \u7ae0 \u00b7 \u524d\u7aef\u770b\u677f static\/index.html<\/h2>\n<h3>\u672c\u7ae0\u76ee\u6807<\/h3>\n<p>\u5199\u4e00\u4e2a\u7eaf HTML &#043; CSS &#043; JS&#xff08;\u65e0\u6846\u67b6&#xff09;\u7684\u524d\u7aef\u9875\u9762&#xff0c;\u5b83\u540c\u65f6&#xff1a;<\/p>\n<ul>\n<li>\u7528 EventSource \u8fde \/sse\/orders \u63a5\u6536 SSE \u63a8\u9001&#xff0c;\u6e32\u67d3\u5de6\u4fa7\u8ba2\u5355\u770b\u677f&#xff1b;<\/li>\n<li>\u7528 WebSocket \u8fde \/ws\/orders \u63a5\u6536\u5e7f\u64ad &#043; \u53d1\u547d\u4ee4&#xff08;ping\/add\/snapshot&#xff09;&#xff0c;\u6e32\u67d3\u53f3\u4fa7\u64cd\u4f5c\u53f0\u548c\u901a\u4fe1\u65e5\u5fd7&#xff1b;<\/li>\n<li>\u65ad\u7ebf\u81ea\u52a8\u91cd\u8fde&#xff1b;<\/li>\n<li>\u628a\u8ba2\u5355\u6e32\u67d3\u6210\u5e26\u8fdb\u5ea6\u6761\u3001\u72b6\u6001\u8272\u5757\u7684\u5361\u7247&#xff0c;\u9876\u90e8\u663e\u793a\u7edf\u8ba1\u548c\u5b9e\u65f6\u65f6\u949f\u3002<\/li>\n<\/ul>\n<p>\u5199\u5b8c\u8fd9\u4e00\u7ae0&#xff0c;\u6574\u4e2a\u9879\u76ee\u5c31\u9f50\u4e86&#xff0c;\u53ef\u4ee5\u8dd1\u8d77\u6765\u770b\u6548\u679c\u3002<\/p>\n<p>\u672c\u7ae0\u4ee3\u7801\u5f88\u957f&#xff08;300 \u591a\u884c&#xff09;&#xff0c;\u4f46\u5168\u662f\u539f\u59cb\u4ee3\u7801&#xff0c;\u7167\u6284\u5373\u53ef\u3002\u8bb2\u89e3\u5206\u300cCSS \/ HTML \/ JS\u300d\u4e09\u5757&#xff0c;\u53ef\u4ee5\u6284\u5b8c\u518d\u770b\u3002<\/p>\n<hr \/>\n<h3>7.1 \u539f\u59cb\u5b8c\u6574\u4ee3\u7801<\/h3>\n<p>\u65b0\u5efa\u6587\u4ef6 static\/index.html&#xff0c;\u5b8c\u6574\u7167\u6284&#xff08;\u8fd9\u4e00\u4efd\u662f\u9879\u76ee\u91cc\u552f\u4e00\u7684\u524d\u7aef\u6587\u4ef6&#xff09;&#xff1a;<\/p>\n<p><span class=\"token doctype\"><span class=\"token punctuation\">&lt;!<\/span><span class=\"token doctype-tag\">DOCTYPE<\/span> <span class=\"token name\">html<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>html<\/span> <span class=\"token attr-name\">lang<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>zh-CN<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>head<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>meta<\/span> <span class=\"token attr-name\">charset<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>utf-8<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>meta<\/span> <span class=\"token attr-name\">name<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>viewport<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">content<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>width&#061;device-width, initial-scale&#061;1<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>title<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>title<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>style<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token style\"><span class=\"token language-css\"><br \/>\n  <span class=\"token comment\">\/* &#8212;&#8212;&#8212;- \u8bbe\u8ba1\u53d8\u91cf &#8212;&#8212;&#8212;- *\/<\/span><br \/>\n  <span class=\"token selector\">:root<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">&#8211;bg<\/span><span class=\"token punctuation\">:<\/span> #faf3e8<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;bg-soft<\/span><span class=\"token punctuation\">:<\/span> #fff8ef<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;card-bg<\/span><span class=\"token punctuation\">:<\/span> #ffffff<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;card-border<\/span><span class=\"token punctuation\">:<\/span> #f0dcc4<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;card-shadow<\/span><span class=\"token punctuation\">:<\/span> 0 4px 16px <span class=\"token function\">rgba<\/span><span class=\"token punctuation\">(<\/span>180<span class=\"token punctuation\">,<\/span> 120<span class=\"token punctuation\">,<\/span> 60<span class=\"token punctuation\">,<\/span> .08<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;text<\/span><span class=\"token punctuation\">:<\/span> #3d2c1e<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;text-soft<\/span><span class=\"token punctuation\">:<\/span> #8d6e63<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;text-mute<\/span><span class=\"token punctuation\">:<\/span> #bca995<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;accent<\/span><span class=\"token punctuation\">:<\/span> #ff7043<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;accent-dark<\/span><span class=\"token punctuation\">:<\/span> #e64a19<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;accent-soft<\/span><span class=\"token punctuation\">:<\/span> #ffe0b2<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;tea<\/span><span class=\"token punctuation\">:<\/span> #ff8a65<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;tea-2<\/span><span class=\"token punctuation\">:<\/span> #ffb74d<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;green<\/span><span class=\"token punctuation\">:<\/span> #66bb6a<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;green-bg<\/span><span class=\"token punctuation\">:<\/span> #e8f5e9<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;blue<\/span><span class=\"token punctuation\">:<\/span> #42a5f5<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;blue-bg<\/span><span class=\"token punctuation\">:<\/span> #e3f2fd<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;gray-bg<\/span><span class=\"token punctuation\">:<\/span> #eceff1<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;radius<\/span><span class=\"token punctuation\">:<\/span> 14px<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">&#8211;radius-sm<\/span><span class=\"token punctuation\">:<\/span> 8px<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><\/p>\n<p>  <span class=\"token selector\">*<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">box-sizing<\/span><span class=\"token punctuation\">:<\/span> border-box<span class=\"token punctuation\">;<\/span> <span class=\"token property\">margin<\/span><span class=\"token punctuation\">:<\/span> 0<span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 0<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">html, body<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">height<\/span><span class=\"token punctuation\">:<\/span> 100%<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">body<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">font-family<\/span><span class=\"token punctuation\">:<\/span> -apple-system<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;PingFang SC&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;Microsoft YaHei&#034;<\/span><span class=\"token punctuation\">,<\/span> system-ui<span class=\"token punctuation\">,<\/span> sans-serif<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;bg<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;text<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">min-height<\/span><span class=\"token punctuation\">:<\/span> 100vh<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">-webkit-font-smoothing<\/span><span class=\"token punctuation\">:<\/span> antialiased<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><\/p>\n<p>  <span class=\"token comment\">\/* &#8212;&#8212;&#8212;- \u9876\u90e8\u5bfc\u822a &#8212;&#8212;&#8212;- *\/<\/span><br \/>\n  <span class=\"token selector\">header<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 0 28px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">height<\/span><span class=\"token punctuation\">:<\/span> 64px<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">linear-gradient<\/span><span class=\"token punctuation\">(<\/span>135deg<span class=\"token punctuation\">,<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;tea<span class=\"token punctuation\">)<\/span> 0%<span class=\"token punctuation\">,<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;tea-2<span class=\"token punctuation\">)<\/span> 100%<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> #fff<span class=\"token punctuation\">;<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 20px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">align-items<\/span><span class=\"token punctuation\">:<\/span> center<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">box-shadow<\/span><span class=\"token punctuation\">:<\/span> 0 2px 12px <span class=\"token function\">rgba<\/span><span class=\"token punctuation\">(<\/span>255<span class=\"token punctuation\">,<\/span> 138<span class=\"token punctuation\">,<\/span> 101<span class=\"token punctuation\">,<\/span> .25<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">position<\/span><span class=\"token punctuation\">:<\/span> sticky<span class=\"token punctuation\">;<\/span> <span class=\"token property\">top<\/span><span class=\"token punctuation\">:<\/span> 0<span class=\"token punctuation\">;<\/span> <span class=\"token property\">z-index<\/span><span class=\"token punctuation\">:<\/span> 100<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">header h1<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 18px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-weight<\/span><span class=\"token punctuation\">:<\/span> 700<span class=\"token punctuation\">;<\/span> <span class=\"token property\">letter-spacing<\/span><span class=\"token punctuation\">:<\/span> .5px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">white-space<\/span><span class=\"token punctuation\">:<\/span> nowrap<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.header-right<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">margin-left<\/span><span class=\"token punctuation\">:<\/span> auto<span class=\"token punctuation\">;<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 10px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">align-items<\/span><span class=\"token punctuation\">:<\/span> center<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.badge<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 12px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 5px 14px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> 999px<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">rgba<\/span><span class=\"token punctuation\">(<\/span>255<span class=\"token punctuation\">,<\/span>255<span class=\"token punctuation\">,<\/span>255<span class=\"token punctuation\">,<\/span>.2<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">backdrop-filter<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">blur<\/span><span class=\"token punctuation\">(<\/span>4px<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">align-items<\/span><span class=\"token punctuation\">:<\/span> center<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 6px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">white-space<\/span><span class=\"token punctuation\">:<\/span> nowrap<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">transition<\/span><span class=\"token punctuation\">:<\/span> background .3s<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.badge .dot<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">width<\/span><span class=\"token punctuation\">:<\/span> 7px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">height<\/span><span class=\"token punctuation\">:<\/span> 7px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> 50%<span class=\"token punctuation\">;<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> #c8e6c9<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.badge .dot.off<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> #ef5350<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.badge .dot.live<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> #c8e6c9<span class=\"token punctuation\">;<\/span> <span class=\"token property\">animation<\/span><span class=\"token punctuation\">:<\/span> pulse 1.5s infinite<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token atrule\"><span class=\"token rule\">&#064;keyframes<\/span> pulse<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token selector\">0%,100%<\/span><span class=\"token punctuation\">{<\/span><span class=\"token property\">opacity<\/span><span class=\"token punctuation\">:<\/span>1<span class=\"token punctuation\">}<\/span> <span class=\"token selector\">50%<\/span><span class=\"token punctuation\">{<\/span><span class=\"token property\">opacity<\/span><span class=\"token punctuation\">:<\/span>.3<span class=\"token punctuation\">}<\/span> <span class=\"token punctuation\">}<\/span><\/p>\n<p>  <span class=\"token comment\">\/* &#8212;&#8212;&#8212;- \u7edf\u8ba1\u6761 &#8212;&#8212;&#8212;- *\/<\/span><br \/>\n  <span class=\"token selector\">.stats-bar<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 12px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 20px 28px 0<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.stat-chip<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">flex<\/span><span class=\"token punctuation\">:<\/span> 1<span class=\"token punctuation\">;<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;card-bg<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">border<\/span><span class=\"token punctuation\">:<\/span> 1px solid <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;card-border<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;radius-sm<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 12px 16px<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">flex-direction<\/span><span class=\"token punctuation\">:<\/span> column<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 2px<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">box-shadow<\/span><span class=\"token punctuation\">:<\/span> 0 2px 8px <span class=\"token function\">rgba<\/span><span class=\"token punctuation\">(<\/span>180<span class=\"token punctuation\">,<\/span>120<span class=\"token punctuation\">,<\/span>60<span class=\"token punctuation\">,<\/span>.06<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.stat-chip .num<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 22px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-weight<\/span><span class=\"token punctuation\">:<\/span> 700<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent-dark<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">line-height<\/span><span class=\"token punctuation\">:<\/span> 1.2<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.stat-chip .lbl<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 11px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;text-soft<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.stat-chip.green .num<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;green<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.stat-chip.blue .num<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;blue<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.stat-chip.gray .num<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;text-soft<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><\/p>\n<p>  <span class=\"token comment\">\/* &#8212;&#8212;&#8212;- \u4e3b\u4f53\u5e03\u5c40 &#8212;&#8212;&#8212;- *\/<\/span><br \/>\n  <span class=\"token selector\">main<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 20px 28px 28px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> grid<span class=\"token punctuation\">;<\/span> <span class=\"token property\">grid-template-columns<\/span><span class=\"token punctuation\">:<\/span> 1.4fr 1fr<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 20px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">align-items<\/span><span class=\"token punctuation\">:<\/span> start<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token atrule\"><span class=\"token rule\">&#064;media<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token property\">max-width<\/span><span class=\"token punctuation\">:<\/span> 880px<span class=\"token punctuation\">)<\/span><\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token selector\">main<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">grid-template-columns<\/span><span class=\"token punctuation\">:<\/span> 1fr<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span> <span class=\"token selector\">.stats-bar<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">flex-wrap<\/span><span class=\"token punctuation\">:<\/span> wrap<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span> <span class=\"token selector\">.stat-chip<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">min-width<\/span><span class=\"token punctuation\">:<\/span> 45%<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">section<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">border<\/span><span class=\"token punctuation\">:<\/span> 1px solid <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;card-border<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;radius<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 18px<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;card-bg<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">box-shadow<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;card-shadow<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">section h2<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 14px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent-dark<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">margin-bottom<\/span><span class=\"token punctuation\">:<\/span> 14px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">align-items<\/span><span class=\"token punctuation\">:<\/span> center<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 6px<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">section h2 .tag<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 10px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-weight<\/span><span class=\"token punctuation\">:<\/span> 600<span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 2px 8px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> 4px<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent-soft<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent-dark<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><\/p>\n<p>  <span class=\"token comment\">\/* &#8212;&#8212;&#8212;- \u8ba2\u5355\u5361\u7247 &#8212;&#8212;&#8212;- *\/<\/span><br \/>\n  <span class=\"token selector\">.orders<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> grid<span class=\"token punctuation\">;<\/span> <span class=\"token property\">grid-template-columns<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">repeat<\/span><span class=\"token punctuation\">(<\/span>auto-fill<span class=\"token punctuation\">,<\/span> <span class=\"token function\">minmax<\/span><span class=\"token punctuation\">(<\/span>210px<span class=\"token punctuation\">,<\/span> 1fr<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 12px<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.card<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">border<\/span><span class=\"token punctuation\">:<\/span> 1px solid <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent-soft<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> 10px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 14px<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">linear-gradient<\/span><span class=\"token punctuation\">(<\/span>180deg<span class=\"token punctuation\">,<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;bg-soft<span class=\"token punctuation\">)<\/span> 0%<span class=\"token punctuation\">,<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;card-bg<span class=\"token punctuation\">)<\/span> 100%<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">position<\/span><span class=\"token punctuation\">:<\/span> relative<span class=\"token punctuation\">;<\/span> <span class=\"token property\">transition<\/span><span class=\"token punctuation\">:<\/span> transform .2s<span class=\"token punctuation\">,<\/span> box-shadow .2s<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">overflow<\/span><span class=\"token punctuation\">:<\/span> hidden<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.card:hover<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">transform<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">translateY<\/span><span class=\"token punctuation\">(<\/span>-2px<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">box-shadow<\/span><span class=\"token punctuation\">:<\/span> 0 6px 20px <span class=\"token function\">rgba<\/span><span class=\"token punctuation\">(<\/span>255<span class=\"token punctuation\">,<\/span>138<span class=\"token punctuation\">,<\/span>101<span class=\"token punctuation\">,<\/span>.15<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.card::before<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">content<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#039;&#039;<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">position<\/span><span class=\"token punctuation\">:<\/span> absolute<span class=\"token punctuation\">;<\/span> <span class=\"token property\">left<\/span><span class=\"token punctuation\">:<\/span> 0<span class=\"token punctuation\">;<\/span> <span class=\"token property\">top<\/span><span class=\"token punctuation\">:<\/span> 0<span class=\"token punctuation\">;<\/span> <span class=\"token property\">bottom<\/span><span class=\"token punctuation\">:<\/span> 0<span class=\"token punctuation\">;<\/span> <span class=\"token property\">width<\/span><span class=\"token punctuation\">:<\/span> 4px<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> 4px 0 0 4px<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.card.s-done::before<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;green<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.card.s-picked::before<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;text-mute<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.card .id<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">position<\/span><span class=\"token punctuation\">:<\/span> absolute<span class=\"token punctuation\">;<\/span> <span class=\"token property\">top<\/span><span class=\"token punctuation\">:<\/span> 10px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">right<\/span><span class=\"token punctuation\">:<\/span> 12px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 11px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;text-mute<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-weight<\/span><span class=\"token punctuation\">:<\/span> 600<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.card h3<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">margin-bottom<\/span><span class=\"token punctuation\">:<\/span> 4px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 15px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent-dark<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-weight<\/span><span class=\"token punctuation\">:<\/span> 700<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.card .meta<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 11px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;text-soft<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">margin-bottom<\/span><span class=\"token punctuation\">:<\/span> 10px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">line-height<\/span><span class=\"token punctuation\">:<\/span> 1.6<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.card .meta span<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> inline-block<span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 1px 6px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;bg<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> 4px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">margin<\/span><span class=\"token punctuation\">:<\/span> 2px 2px 0 0<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.bar-wrap<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">align-items<\/span><span class=\"token punctuation\">:<\/span> center<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 8px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">margin-bottom<\/span><span class=\"token punctuation\">:<\/span> 8px<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.bar<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">flex<\/span><span class=\"token punctuation\">:<\/span> 1<span class=\"token punctuation\">;<\/span> <span class=\"token property\">height<\/span><span class=\"token punctuation\">:<\/span> 6px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent-soft<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> 3px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">overflow<\/span><span class=\"token punctuation\">:<\/span> hidden<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.bar &gt; div<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">height<\/span><span class=\"token punctuation\">:<\/span> 100%<span class=\"token punctuation\">;<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">linear-gradient<\/span><span class=\"token punctuation\">(<\/span>90deg<span class=\"token punctuation\">,<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;tea-2<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">transition<\/span><span class=\"token punctuation\">:<\/span> width .5s <span class=\"token function\">cubic-bezier<\/span><span class=\"token punctuation\">(<\/span>.4<span class=\"token punctuation\">,<\/span>0<span class=\"token punctuation\">,<\/span>.2<span class=\"token punctuation\">,<\/span>1<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> 3px<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.bar-wrap .pct<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 11px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;text-soft<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-weight<\/span><span class=\"token punctuation\">:<\/span> 600<span class=\"token punctuation\">;<\/span> <span class=\"token property\">min-width<\/span><span class=\"token punctuation\">:<\/span> 32px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">text-align<\/span><span class=\"token punctuation\">:<\/span> right<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.status<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> inline-flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">align-items<\/span><span class=\"token punctuation\">:<\/span> center<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 4px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 3px 10px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> 999px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 11px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-weight<\/span><span class=\"token punctuation\">:<\/span> 600<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.status::before<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">content<\/span><span class=\"token punctuation\">:<\/span><span class=\"token string\">&#039;&#039;<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">width<\/span><span class=\"token punctuation\">:<\/span>5px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">height<\/span><span class=\"token punctuation\">:<\/span>5px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span>50%<span class=\"token punctuation\">;<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> currentColor<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.s-\u5f85\u5236\u4f5c<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> #fff3e0<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> #ef6c00<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.s-\u5236\u4f5c\u4e2d<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> #ffe0b2<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> #e65100<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.s-\u5236\u4f5c\u4e2d::before<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">animation<\/span><span class=\"token punctuation\">:<\/span> pulse 1.2s infinite<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.s-\u5df2\u5b8c\u6210<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;green-bg<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> #2e7d32<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.s-\u5df2\u53d6\u9910<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;gray-bg<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> #607d8b<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><\/p>\n<p>  <span class=\"token comment\">\/* &#8212;&#8212;&#8212;- \u63a7\u5236\u9762\u677f &#8212;&#8212;&#8212;- *\/<\/span><br \/>\n  <span class=\"token selector\">.panel<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">flex-direction<\/span><span class=\"token punctuation\">:<\/span> column<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 12px<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">input<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">width<\/span><span class=\"token punctuation\">:<\/span> 100%<span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 10px 14px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;bg-soft<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">border<\/span><span class=\"token punctuation\">:<\/span> 1px solid <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;card-border<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;radius-sm<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">font<\/span><span class=\"token punctuation\">:<\/span> inherit<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;text<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">transition<\/span><span class=\"token punctuation\">:<\/span> border-color .2s<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">input:focus<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">outline<\/span><span class=\"token punctuation\">:<\/span> none<span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.btn-row<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 8px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">flex-wrap<\/span><span class=\"token punctuation\">:<\/span> wrap<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">button<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 9px 18px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">border<\/span><span class=\"token punctuation\">:<\/span> 0<span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;radius-sm<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> #fff<span class=\"token punctuation\">;<\/span> <span class=\"token property\">cursor<\/span><span class=\"token punctuation\">:<\/span> pointer<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font<\/span><span class=\"token punctuation\">:<\/span> inherit<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-weight<\/span><span class=\"token punctuation\">:<\/span> 600<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 13px<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">transition<\/span><span class=\"token punctuation\">:<\/span> all .2s<span class=\"token punctuation\">;<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">align-items<\/span><span class=\"token punctuation\">:<\/span> center<span class=\"token punctuation\">;<\/span> <span class=\"token property\">gap<\/span><span class=\"token punctuation\">:<\/span> 4px<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">button:hover<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent-dark<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">transform<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">translateY<\/span><span class=\"token punctuation\">(<\/span>-1px<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">box-shadow<\/span><span class=\"token punctuation\">:<\/span> 0 3px 10px <span class=\"token function\">rgba<\/span><span class=\"token punctuation\">(<\/span>255<span class=\"token punctuation\">,<\/span>112<span class=\"token punctuation\">,<\/span>67<span class=\"token punctuation\">,<\/span>.3<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">button:active<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">transform<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">translateY<\/span><span class=\"token punctuation\">(<\/span>0<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">button.ghost<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent-soft<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;accent-dark<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">button.ghost:hover<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> #ffcc80<span class=\"token punctuation\">;<\/span> <span class=\"token property\">box-shadow<\/span><span class=\"token punctuation\">:<\/span> 0 3px 10px <span class=\"token function\">rgba<\/span><span class=\"token punctuation\">(<\/span>255<span class=\"token punctuation\">,<\/span>224<span class=\"token punctuation\">,<\/span>178<span class=\"token punctuation\">,<\/span>.5<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><\/p>\n<p>  <span class=\"token comment\">\/* &#8212;&#8212;&#8212;- WS \u65e5\u5fd7 &#8212;&#8212;&#8212;- *\/<\/span><br \/>\n  <span class=\"token selector\">.log-header<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> flex<span class=\"token punctuation\">;<\/span> <span class=\"token property\">justify-content<\/span><span class=\"token punctuation\">:<\/span> space-between<span class=\"token punctuation\">;<\/span> <span class=\"token property\">align-items<\/span><span class=\"token punctuation\">:<\/span> center<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.log-header span<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 11px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;text-mute<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">pre<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">background<\/span><span class=\"token punctuation\">:<\/span> #2d2018<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> #ffe0b2<span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 12px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-radius<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;radius-sm<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">overflow<\/span><span class=\"token punctuation\">:<\/span> auto<span class=\"token punctuation\">;<\/span> <span class=\"token property\">max-height<\/span><span class=\"token punctuation\">:<\/span> 220px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 11px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">line-height<\/span><span class=\"token punctuation\">:<\/span> 1.6<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token property\">font-family<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;SF Mono&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;Cascadia Code&#034;<\/span><span class=\"token punctuation\">,<\/span> Consolas<span class=\"token punctuation\">,<\/span> monospace<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">pre .arrow-in<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> #66bb6a<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">pre .arrow-out<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> #ffb74d<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">pre .type<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> #42a5f5<span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-weight<\/span><span class=\"token punctuation\">:<\/span> 600<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><\/p>\n<p>  <span class=\"token comment\">\/* &#8212;&#8212;&#8212;- \u7a7a\u72b6\u6001 &#8212;&#8212;&#8212;- *\/<\/span><br \/>\n  <span class=\"token selector\">.empty<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token property\">text-align<\/span><span class=\"token punctuation\">:<\/span> center<span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding<\/span><span class=\"token punctuation\">:<\/span> 32px 16px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;text-mute<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 13px<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.empty .icon<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 28px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">display<\/span><span class=\"token punctuation\">:<\/span> block<span class=\"token punctuation\">;<\/span> <span class=\"token property\">margin-bottom<\/span><span class=\"token punctuation\">:<\/span> 8px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">opacity<\/span><span class=\"token punctuation\">:<\/span> .5<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><\/p>\n<p>  <span class=\"token selector\">.meta-line<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">font-size<\/span><span class=\"token punctuation\">:<\/span> 11px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;text-soft<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token property\">margin-top<\/span><span class=\"token punctuation\">:<\/span> 10px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">padding-top<\/span><span class=\"token punctuation\">:<\/span> 10px<span class=\"token punctuation\">;<\/span> <span class=\"token property\">border-top<\/span><span class=\"token punctuation\">:<\/span> 1px dashed <span class=\"token function\">var<\/span><span class=\"token punctuation\">(<\/span>&#8211;card-border<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><\/p>\n<p>  <span class=\"token comment\">\/* &#8212;&#8212;&#8212;- \u5361\u7247\u5165\u573a\u52a8\u753b &#8212;&#8212;&#8212;- *\/<\/span><br \/>\n  <span class=\"token atrule\"><span class=\"token rule\">&#064;keyframes<\/span> cardIn<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token selector\">from<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">opacity<\/span><span class=\"token punctuation\">:<\/span>0<span class=\"token punctuation\">;<\/span> <span class=\"token property\">transform<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">translateY<\/span><span class=\"token punctuation\">(<\/span>8px<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span> <span class=\"token selector\">to<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">opacity<\/span><span class=\"token punctuation\">:<\/span>1<span class=\"token punctuation\">;<\/span> <span class=\"token property\">transform<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">translateY<\/span><span class=\"token punctuation\">(<\/span>0<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token selector\">.card<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token property\">animation<\/span><span class=\"token punctuation\">:<\/span> cardIn .3s ease-out<span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>style<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>head<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>body<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>header<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>h1<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>&#x1f9cb; \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>h1<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>header-right<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>badge<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>dot off<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>sse-dot<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>sse-status<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>SSE: &#8230;<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>badge<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>dot off<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>ws-dot<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>ws-status<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>WS: &#8230;<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>badge<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>clock<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>&#8211;:&#8211;:&#8211;<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>header<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><\/p>\n<p><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>stats-bar<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>stat-chip<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>num<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>stat-total<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>0<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>lbl<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\u603b\u8ba2\u5355<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>stat-chip<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>num<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>stat-making<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>0<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>lbl<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\u5236\u4f5c\u4e2d<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>stat-chip green<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>num<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>stat-done<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>0<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>lbl<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\u5df2\u5b8c\u6210<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>stat-chip gray<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>num<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>stat-picked<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>0<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>lbl<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\u5df2\u53d6\u9910<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><\/p>\n<p><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>main<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>section<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>h2<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>&#x1f4cb; \u5b9e\u65f6\u8ba2\u5355 <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>tag<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>SSE \u5355\u5411\u63a8\u9001<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>h2<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>orders<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>sse-orders<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>empty<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>icon<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>&#x1f9cb;<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\u7b49\u5f85\u65b0\u8ba2\u5355&#8230;<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>meta-line<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>sse-meta<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\u5c1a\u672a\u8fde\u63a5<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>section<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>section<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>h2<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>&#x1f39b;\ufe0f \u5e97\u5458\u64cd\u4f5c\u53f0 <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>tag<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>WebSocket \u53cc\u5411\u901a\u9053<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>h2<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>orders<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>ws-orders<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token special-attr\"><span class=\"token attr-name\">style<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span><span class=\"token value css language-css\"><span class=\"token property\">margin-bottom<\/span><span class=\"token punctuation\">:<\/span>14px<\/span><span class=\"token punctuation\">&#034;<\/span><\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>empty<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>icon<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>&#x1f39b;\ufe0f<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\u7b49\u5f85\u65b0\u8ba2\u5355&#8230;<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>panel<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>input<\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>cmd<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token attr-name\">placeholder<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#039;<\/span>{&#034;cmd&#034;:&#034;pickup&#034;,&#034;arg&#034;:3}  \u6216  {&#034;cmd&#034;:&#034;add&#034;}<span class=\"token punctuation\">&#039;<\/span><\/span> <span class=\"token punctuation\">\/&gt;<\/span><\/span><br \/>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>btn-row<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>button<\/span> <span class=\"token special-attr\"><span class=\"token attr-name\">onclick<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#039;<\/span><span class=\"token value javascript language-javascript\"><span class=\"token function\">sendCmd<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">cmd<\/span><span class=\"token operator\">:<\/span><span class=\"token string\">&#034;ping&#034;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/span><span class=\"token punctuation\">&#039;<\/span><\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>&#x1f4e1; ping<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>button<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>button<\/span> <span class=\"token special-attr\"><span class=\"token attr-name\">onclick<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#039;<\/span><span class=\"token value javascript language-javascript\"><span class=\"token function\">sendCmd<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">cmd<\/span><span class=\"token operator\">:<\/span><span class=\"token string\">&#034;add&#034;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/span><span class=\"token punctuation\">&#039;<\/span><\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\u2795 \u52a0\u5355<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>button<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>button<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>ghost<span class=\"token punctuation\">&#034;<\/span><\/span> <span class=\"token special-attr\"><span class=\"token attr-name\">onclick<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#039;<\/span><span class=\"token value javascript language-javascript\"><span class=\"token function\">sendCmd<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">cmd<\/span><span class=\"token operator\">:<\/span><span class=\"token string\">&#034;snapshot&#034;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/span><span class=\"token punctuation\">&#039;<\/span><\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>&#x1f4f8; snapshot<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>button<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>log-header<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>WS \u901a\u4fe1\u65e5\u5fd7<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>span<\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>ws-log-count<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>0 \u6761<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>span<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>pre<\/span> <span class=\"token attr-name\">id<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">&#061;<\/span><span class=\"token punctuation\">&#034;<\/span>ws-log<span class=\"token punctuation\">&#034;<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>pre<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>section<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>main<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><\/p>\n<p><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>script<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token script\"><span class=\"token language-javascript\"><br \/>\n  <span class=\"token keyword\">const<\/span> <span class=\"token constant\">STATUS_CLASS<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token string-property property\">&#039;\u5f85\u5236\u4f5c&#039;<\/span><span class=\"token operator\">:<\/span><span class=\"token string\">&#039;s-\u5f85\u5236\u4f5c&#039;<\/span><span class=\"token punctuation\">,<\/span><span class=\"token string-property property\">&#039;\u5236\u4f5c\u4e2d&#039;<\/span><span class=\"token operator\">:<\/span><span class=\"token string\">&#039;s-\u5236\u4f5c\u4e2d&#039;<\/span><span class=\"token punctuation\">,<\/span><span class=\"token string-property property\">&#039;\u5df2\u5b8c\u6210&#039;<\/span><span class=\"token operator\">:<\/span><span class=\"token string\">&#039;s-\u5df2\u5b8c\u6210&#039;<\/span><span class=\"token punctuation\">,<\/span><span class=\"token string-property property\">&#039;\u5df2\u53d6\u9910&#039;<\/span><span class=\"token operator\">:<\/span><span class=\"token string\">&#039;s-\u5df2\u53d6\u9910&#039;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token keyword\">const<\/span> <span class=\"token constant\">STATUS_CARD<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token string-property property\">&#039;\u5df2\u5b8c\u6210&#039;<\/span><span class=\"token operator\">:<\/span><span class=\"token string\">&#039;s-done&#039;<\/span><span class=\"token punctuation\">,<\/span><span class=\"token string-property property\">&#039;\u5df2\u53d6\u9910&#039;<\/span><span class=\"token operator\">:<\/span><span class=\"token string\">&#039;s-picked&#039;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/p>\n<p>  <span class=\"token keyword\">const<\/span> <span class=\"token function-variable function\">fmtTime<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">iso<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> d <span class=\"token operator\">&#061;<\/span> <span class=\"token keyword\">new<\/span> <span class=\"token class-name\">Date<\/span><span class=\"token punctuation\">(<\/span>iso<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token keyword\">return<\/span> d<span class=\"token punctuation\">.<\/span><span class=\"token function\">toLocaleTimeString<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;zh-CN&#039;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">hour12<\/span><span class=\"token operator\">:<\/span> <span class=\"token boolean\">false<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/p>\n<p>  <span class=\"token comment\">\/\/ \u66f4\u65b0\u7edf\u8ba1\u6761<\/span><br \/>\n  <span class=\"token keyword\">function<\/span> <span class=\"token function\">updateStats<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\">list<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> s <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token literal-property property\">total<\/span><span class=\"token operator\">:<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token literal-property property\">making<\/span><span class=\"token operator\">:<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token literal-property property\">done<\/span><span class=\"token operator\">:<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token literal-property property\">picked<\/span><span class=\"token operator\">:<\/span><span class=\"token number\">0<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">for<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token keyword\">const<\/span> o <span class=\"token keyword\">of<\/span> <span class=\"token punctuation\">(<\/span>list <span class=\"token operator\">||<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n      s<span class=\"token punctuation\">.<\/span>total<span class=\"token operator\">&#043;&#043;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      <span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span>o<span class=\"token punctuation\">.<\/span>status <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;\u5236\u4f5c\u4e2d&#039;<\/span> <span class=\"token operator\">||<\/span> o<span class=\"token punctuation\">.<\/span>status <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;\u5f85\u5236\u4f5c&#039;<\/span><span class=\"token punctuation\">)<\/span> s<span class=\"token punctuation\">.<\/span>making<span class=\"token operator\">&#043;&#043;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      <span class=\"token keyword\">else<\/span> <span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span>o<span class=\"token punctuation\">.<\/span>status <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;\u5df2\u5b8c\u6210&#039;<\/span><span class=\"token punctuation\">)<\/span> s<span class=\"token punctuation\">.<\/span>done<span class=\"token operator\">&#043;&#043;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      <span class=\"token keyword\">else<\/span> <span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span>o<span class=\"token punctuation\">.<\/span>status <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;\u5df2\u53d6\u9910&#039;<\/span><span class=\"token punctuation\">)<\/span> s<span class=\"token punctuation\">.<\/span>picked<span class=\"token operator\">&#043;&#043;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token punctuation\">}<\/span><br \/>\n    document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;stat-total&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> s<span class=\"token punctuation\">.<\/span>total<span class=\"token punctuation\">;<\/span><br \/>\n    document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;stat-making&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> s<span class=\"token punctuation\">.<\/span>making<span class=\"token punctuation\">;<\/span><br \/>\n    document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;stat-done&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> s<span class=\"token punctuation\">.<\/span>done<span class=\"token punctuation\">;<\/span><br \/>\n    document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;stat-picked&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> s<span class=\"token punctuation\">.<\/span>picked<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><\/p>\n<p>  <span class=\"token keyword\">const<\/span> <span class=\"token function-variable function\">renderOrders<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">el<span class=\"token punctuation\">,<\/span> list<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token operator\">!<\/span>list <span class=\"token operator\">||<\/span> <span class=\"token operator\">!<\/span>list<span class=\"token punctuation\">.<\/span>length<span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n      el<span class=\"token punctuation\">.<\/span>innerHTML <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;&lt;div class&#061;&#034;empty&#034;&gt;&lt;span class&#061;&#034;icon&#034;&gt;&#x1f9cb;&lt;\/span&gt;\u6682\u65e0\u8ba2\u5355&lt;\/div&gt;&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      <span class=\"token function\">updateStats<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      <span class=\"token keyword\">return<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token punctuation\">}<\/span><br \/>\n    el<span class=\"token punctuation\">.<\/span>innerHTML <span class=\"token operator\">&#061;<\/span> list<span class=\"token punctuation\">.<\/span><span class=\"token function\">map<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\">o<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">&#096;<\/span><span class=\"token string\"><br \/>\n      &lt;div class&#061;&#034;card <\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span><span class=\"token constant\">STATUS_CARD<\/span><span class=\"token punctuation\">[<\/span>o<span class=\"token punctuation\">.<\/span>status<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">||<\/span> <span class=\"token string\">&#039;&#039;<\/span><span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&#034;&gt;<br \/>\n        &lt;span class&#061;&#034;id&#034;&gt;#<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>id<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt;<br \/>\n        &lt;h3&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>drink<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/h3&gt;<br \/>\n        &lt;div class&#061;&#034;meta&#034;&gt;<br \/>\n          &lt;span&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>base<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt;&lt;span&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>sugar<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt;&lt;span&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>ice<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt;&lt;span&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>topping<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt;&lt;span&gt;\u00a5<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>price<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt;<br \/>\n        &lt;\/div&gt;<br \/>\n        &lt;div class&#061;&#034;bar-wrap&#034;&gt;<br \/>\n          &lt;div class&#061;&#034;bar&#034;&gt;&lt;div style&#061;&#034;width:<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>progress<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">%&#034;&gt;&lt;\/div&gt;&lt;\/div&gt;<br \/>\n          &lt;span class&#061;&#034;pct&#034;&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>progress<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">%&lt;\/span&gt;<br \/>\n        &lt;\/div&gt;<br \/>\n        &lt;span class&#061;&#034;status <\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span><span class=\"token constant\">STATUS_CLASS<\/span><span class=\"token punctuation\">[<\/span>o<span class=\"token punctuation\">.<\/span>status<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">||<\/span> <span class=\"token string\">&#039;&#039;<\/span><span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&#034;&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>status<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt;<br \/>\n        &lt;span class&#061;&#034;meta-line&#034; style&#061;&#034;margin-left:8px;border:0;padding:0&#034;&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span><span class=\"token function\">fmtTime<\/span><span class=\"token punctuation\">(<\/span>o<span class=\"token punctuation\">.<\/span>created_at<span class=\"token punctuation\">)<\/span><span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt;<br \/>\n      &lt;\/div&gt;<br \/>\n    <\/span><span class=\"token template-punctuation string\">&#096;<\/span><\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">join<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token function\">updateStats<\/span><span class=\"token punctuation\">(<\/span>list<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/p>\n<p>  <span class=\"token comment\">\/\/ &#8212;&#8212;&#8212;- SSE &#8212;&#8212;&#8212;-<\/span><br \/>\n  <span class=\"token keyword\">function<\/span> <span class=\"token function\">connectSSE<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> es <span class=\"token operator\">&#061;<\/span> <span class=\"token keyword\">new<\/span> <span class=\"token class-name\">EventSource<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;\/sse\/orders&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> status <span class=\"token operator\">&#061;<\/span> document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;sse-status&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> dot <span class=\"token operator\">&#061;<\/span> document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;sse-dot&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> meta <span class=\"token operator\">&#061;<\/span> document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;sse-meta&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> box <span class=\"token operator\">&#061;<\/span> document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;sse-orders&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    es<span class=\"token punctuation\">.<\/span><span class=\"token function\">addEventListener<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;hello&#039;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">e<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n      status<span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;SSE: \u5df2\u8fde\u63a5&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      dot<span class=\"token punctuation\">.<\/span>className <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;dot live&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      <span class=\"token keyword\">const<\/span> info <span class=\"token operator\">&#061;<\/span> <span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">parse<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>data<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      meta<span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;\u83dc\u5355: &#039;<\/span> <span class=\"token operator\">&#043;<\/span> info<span class=\"token punctuation\">.<\/span>menu<span class=\"token punctuation\">.<\/span><span class=\"token function\">join<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039; \/ &#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    es<span class=\"token punctuation\">.<\/span><span class=\"token function\">addEventListener<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;orders&#039;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">e<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n      <span class=\"token keyword\">const<\/span> <span class=\"token punctuation\">{<\/span> time<span class=\"token punctuation\">,<\/span> orders <span class=\"token punctuation\">}<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">parse<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>data<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      <span class=\"token function\">renderOrders<\/span><span class=\"token punctuation\">(<\/span>box<span class=\"token punctuation\">,<\/span> orders<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;clock&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token function\">fmtTime<\/span><span class=\"token punctuation\">(<\/span>time<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    es<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onerror<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n      status<span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;SSE: \u65ad\u5f00, 3s \u540e\u91cd\u8fde&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      dot<span class=\"token punctuation\">.<\/span>className <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;dot off&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      es<span class=\"token punctuation\">.<\/span><span class=\"token function\">close<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token function\">setTimeout<\/span><span class=\"token punctuation\">(<\/span>connectSSE<span class=\"token punctuation\">,<\/span> <span class=\"token number\">3000<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token function\">connectSSE<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><\/p>\n<p>  <span class=\"token comment\">\/\/ &#8212;&#8212;&#8212;- WebSocket &#8212;&#8212;&#8212;-<\/span><br \/>\n  <span class=\"token keyword\">const<\/span> log <span class=\"token operator\">&#061;<\/span> document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;ws-log&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token keyword\">let<\/span> logCount <span class=\"token operator\">&#061;<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token keyword\">const<\/span> <span class=\"token function-variable function\">wsLog<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">m<span class=\"token punctuation\">,<\/span> dir<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> line <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token keyword\">typeof<\/span> m <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;string&#039;<\/span> <span class=\"token operator\">?<\/span> m <span class=\"token operator\">:<\/span> <span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span>m<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> arrow <span class=\"token operator\">&#061;<\/span> dir <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;out&#039;<\/span> <span class=\"token operator\">?<\/span> <span class=\"token string\">&#039;&lt;span class&#061;&#034;arrow-out&#034;&gt;\u2192&lt;\/span&gt;&#039;<\/span> <span class=\"token operator\">:<\/span> <span class=\"token string\">&#039;&lt;span class&#061;&#034;arrow-in&#034;&gt;\u2190&lt;\/span&gt;&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token comment\">\/\/ \u9ad8\u4eae type \u5b57\u6bb5<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> colored <span class=\"token operator\">&#061;<\/span> line<span class=\"token punctuation\">.<\/span><span class=\"token function\">replace<\/span><span class=\"token punctuation\">(<\/span><span class=\"token regex\"><span class=\"token regex-delimiter\">\/<\/span><span class=\"token regex-source language-regex\">&#034;type&#034;:&#034;([^&#034;]&#043;)&#034;<\/span><span class=\"token regex-delimiter\">\/<\/span><span class=\"token regex-flags\">g<\/span><\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#039;&#034;type&#034;:&#034;&lt;span class&#061;&#034;type&#034;&gt;$1&lt;\/span&gt;&#034;&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    log<span class=\"token punctuation\">.<\/span>innerHTML <span class=\"token operator\">&#061;<\/span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">&#096;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>arrow<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\"> <\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>colored<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">\\\\n<\/span><span class=\"token template-punctuation string\">&#096;<\/span><\/span> <span class=\"token operator\">&#043;<\/span> log<span class=\"token punctuation\">.<\/span>innerHTML<span class=\"token punctuation\">.<\/span><span class=\"token function\">split<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;\\\\n&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">slice<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">40<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">join<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;\\\\n&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    logCount<span class=\"token operator\">&#043;&#043;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;ws-log-count&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> logCount <span class=\"token operator\">&#043;<\/span> <span class=\"token string\">&#039; \u6761&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token keyword\">function<\/span> <span class=\"token function\">connectWS<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> proto <span class=\"token operator\">&#061;<\/span> location<span class=\"token punctuation\">.<\/span>protocol <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;https:&#039;<\/span> <span class=\"token operator\">?<\/span> <span class=\"token string\">&#039;wss&#039;<\/span> <span class=\"token operator\">:<\/span> <span class=\"token string\">&#039;ws&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> ws <span class=\"token operator\">&#061;<\/span> <span class=\"token keyword\">new<\/span> <span class=\"token class-name\">WebSocket<\/span><span class=\"token punctuation\">(<\/span><span class=\"token template-string\"><span class=\"token template-punctuation string\">&#096;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>proto<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">:\/\/<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>location<span class=\"token punctuation\">.<\/span>host<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">\/ws\/orders<\/span><span class=\"token template-punctuation string\">&#096;<\/span><\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> status <span class=\"token operator\">&#061;<\/span> document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;ws-status&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> dot <span class=\"token operator\">&#061;<\/span> document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;ws-dot&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> box <span class=\"token operator\">&#061;<\/span> document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;ws-orders&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    ws<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onopen<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span> status<span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;WS: \u5df2\u8fde\u63a5&#039;<\/span><span class=\"token punctuation\">;<\/span> dot<span class=\"token punctuation\">.<\/span>className <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;dot live&#039;<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    ws<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onmessage<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">e<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n      <span class=\"token keyword\">const<\/span> msg <span class=\"token operator\">&#061;<\/span> <span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">parse<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>data<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      <span class=\"token function\">wsLog<\/span><span class=\"token punctuation\">(<\/span>msg<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#039;in&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      <span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span>msg<span class=\"token punctuation\">.<\/span>type <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;hello&#039;<\/span> <span class=\"token operator\">||<\/span> msg<span class=\"token punctuation\">.<\/span>type <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;snapshot&#039;<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n        <span class=\"token function\">renderOrders<\/span><span class=\"token punctuation\">(<\/span>box<span class=\"token punctuation\">,<\/span> msg<span class=\"token punctuation\">.<\/span>orders <span class=\"token operator\">||<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n      <span class=\"token punctuation\">}<\/span><br \/>\n    <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    ws<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onclose<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span> status<span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;WS: \u65ad\u5f00, 3s \u540e\u91cd\u8fde&#039;<\/span><span class=\"token punctuation\">;<\/span> dot<span class=\"token punctuation\">.<\/span>className <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;dot off&#039;<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token function\">setTimeout<\/span><span class=\"token punctuation\">(<\/span>connectWS<span class=\"token punctuation\">,<\/span> <span class=\"token number\">3000<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    window<span class=\"token punctuation\">.<\/span>_ws <span class=\"token operator\">&#061;<\/span> ws<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token function\">connectWS<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token keyword\">function<\/span> <span class=\"token function\">sendCmd<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\">obj<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> ws <span class=\"token operator\">&#061;<\/span> window<span class=\"token punctuation\">.<\/span>_ws<span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token operator\">!<\/span>ws <span class=\"token operator\">||<\/span> ws<span class=\"token punctuation\">.<\/span>readyState <span class=\"token operator\">!&#061;&#061;<\/span> <span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">return<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    ws<span class=\"token punctuation\">.<\/span><span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span>obj<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token function\">wsLog<\/span><span class=\"token punctuation\">(<\/span>obj<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#039;out&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><br \/>\n  document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;cmd&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">addEventListener<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;keydown&#039;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">e<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>key <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;Enter&#039;<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token keyword\">try<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token function\">sendCmd<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">parse<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>target<span class=\"token punctuation\">.<\/span>value<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span> <span class=\"token keyword\">catch<\/span> <span class=\"token punctuation\">(<\/span>_<span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">}<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>script<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>body<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><br \/>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>html<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><\/p>\n<hr \/>\n<h3>7.2 \u4ee3\u7801\u7ed3\u6784\u603b\u89c8<\/h3>\n<p>index.html<br \/>\n\u251c\u2500\u2500 &lt;head&gt;<br \/>\n\u2502   \u251c\u2500\u2500 &lt;meta&gt; \u7f16\u7801\/\u89c6\u53e3<br \/>\n\u2502   \u2514\u2500\u2500 &lt;style&gt;  \u5168\u90e8 CSS&#xff08;\u8bbe\u8ba1\u53d8\u91cf &#043; \u5404\u533a\u5757\u6837\u5f0f&#xff09;<br \/>\n\u251c\u2500\u2500 &lt;body&gt;<br \/>\n\u2502   \u251c\u2500\u2500 &lt;header&gt;  \u6807\u9898 &#043; SSE\/WS \u72b6\u6001\u706f &#043; \u65f6\u949f<br \/>\n\u2502   \u251c\u2500\u2500 &lt;div class&#061;&#034;stats-bar&#034;&gt;  4 \u4e2a\u7edf\u8ba1 chip<br \/>\n\u2502   \u251c\u2500\u2500 &lt;main&gt;<br \/>\n\u2502   \u2502   \u251c\u2500\u2500 &lt;section&gt; \u5de6&#xff1a;SSE \u5b9e\u65f6\u8ba2\u5355&#xff08;\u5361\u7247\u7f51\u683c&#xff09;<br \/>\n\u2502   \u2502   \u2514\u2500\u2500 &lt;section&gt; \u53f3&#xff1a;WS \u64cd\u4f5c\u53f0&#xff08;\u5361\u7247 &#043; \u8f93\u5165\u6846 &#043; \u6309\u94ae &#043; \u65e5\u5fd7&#xff09;<br \/>\n\u2502   \u2514\u2500\u2500 &lt;script&gt;  \u5168\u90e8 JS&#xff08;\u6e32\u67d3 &#043; SSE \u8fde\u63a5 &#043; WS \u8fde\u63a5 &#043; \u547d\u4ee4\u53d1\u9001&#xff09;<\/p>\n<h3>7.3 CSS \u8bb2\u89e3&#xff08;\u8bbe\u8ba1\u53d8\u91cf &#043; \u5173\u952e\u6837\u5f0f&#xff09;<\/h3>\n<h4>7.3.1 \u8bbe\u8ba1\u53d8\u91cf :root<\/h4>\n<p><span class=\"token selector\">:root<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n  <span class=\"token property\">&#8211;bg<\/span><span class=\"token punctuation\">:<\/span> #faf3e8<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token property\">&#8211;accent<\/span><span class=\"token punctuation\">:<\/span> #ff7043<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token property\">&#8211;tea<\/span><span class=\"token punctuation\">:<\/span> #ff8a65<span class=\"token punctuation\">;<\/span><br \/>\n  &#8230;<br \/>\n<span class=\"token punctuation\">}<\/span><\/p>\n<ul>\n<li>\u628a\u6240\u6709\u989c\u8272\u3001\u5706\u89d2\u62bd\u6210 CSS \u53d8\u91cf&#xff0c;\u7edf\u4e00\u7ba1\u7406\u300c\u5976\u8336\u6696\u8272\u8c03\u300d\u4e3b\u9898&#xff1b;<\/li>\n<li>\u6539\u4e3b\u9898\u53ea\u8981\u52a8 :root \u91cc\u7684\u503c&#xff0c;\u4e0d\u7528\u5168\u5c40\u641c\u66ff\u6362\u3002<\/li>\n<\/ul>\n<h4>7.3.2 \u5173\u952e\u6837\u5f0f<\/h4>\n<ul>\n<li>.badge .dot.live&#xff1a;\u8fde\u63a5\u6210\u529f\u65f6\u5c0f\u7eff\u70b9 &#043; pulse \u52a8\u753b&#xff08;\u900f\u660e\u5ea6\u95ea\u70c1&#xff09;&#xff0c;\u8868\u793a\u300c\u6d3b\u7740\u300d&#xff1b;<\/li>\n<li>.card::before&#xff1a;\u6bcf\u5f20\u8ba2\u5355\u5361\u7247\u5de6\u4fa7 4px \u8272\u6761&#xff0c;\u989c\u8272\u968f\u72b6\u6001\u53d8&#xff08;\u9ed8\u8ba4\u6a59\u3001s-done \u7eff\u3001s-picked \u7070&#xff09;&#xff1b;<\/li>\n<li>.s-\u5236\u4f5c\u4e2d::before&#xff1a;\u5236\u4f5c\u4e2d\u7684\u72b6\u6001\u70b9\u4e5f\u6709 pulse \u52a8\u753b&#xff0c;\u89c6\u89c9\u4e0a\u300c\u5728\u52a8\u300d&#xff1b;<\/li>\n<li>.bar &gt; div&#xff1a;\u8fdb\u5ea6\u6761&#xff0c;transition: width .5s \u8ba9\u8fdb\u5ea6\u53d8\u5316\u6709\u5e73\u6ed1\u8fc7\u6e21&#xff1b;<\/li>\n<li>&#064;keyframes cardIn&#xff1a;\u8ba2\u5355\u5361\u7247\u5165\u573a\u52a8\u753b&#xff08;\u6de1\u5165 &#043; \u4e0a\u79fb&#xff09;&#xff0c;\u65b0\u589e\u8ba2\u5355\u6709\u300c\u5192\u51fa\u6765\u300d\u7684\u611f\u89c9&#xff1b;<\/li>\n<li>&#064;media (max-width: 880px)&#xff1a;\u7a84\u5c4f\u65f6\u4e3b\u4f53\u53d8\u5355\u5217\u3001\u7edf\u8ba1\u6761\u6362\u884c&#xff0c;\u54cd\u5e94\u5f0f\u3002<\/li>\n<\/ul>\n<h3>7.4 HTML \u8bb2\u89e3&#xff08;\u5173\u952e id&#xff09;<\/h3>\n<p>\u9875\u9762\u91cc\u5f88\u591a\u5143\u7d20\u5e26 id&#xff0c;JS \u9760\u8fd9\u4e9b id \u64cd\u4f5c\u5b83\u4eec&#xff1a;<\/p>\n<table>\n<tr>id\u4f5c\u7528<\/tr>\n<tbody>\n<tr>\n<td>sse-dot \/ sse-status<\/td>\n<td>SSE \u8fde\u63a5\u72b6\u6001\u706f \/ \u6587\u5b57<\/td>\n<\/tr>\n<tr>\n<td>ws-dot \/ ws-status<\/td>\n<td>WS \u8fde\u63a5\u72b6\u6001\u706f \/ \u6587\u5b57<\/td>\n<\/tr>\n<tr>\n<td>clock<\/td>\n<td>\u9876\u90e8\u5b9e\u65f6\u65f6\u949f<\/td>\n<\/tr>\n<tr>\n<td>stat-total\/making\/done\/picked<\/td>\n<td>4 \u4e2a\u7edf\u8ba1\u6570\u5b57<\/td>\n<\/tr>\n<tr>\n<td>sse-orders<\/td>\n<td>\u5de6\u4fa7 SSE \u8ba2\u5355\u5361\u7247\u5bb9\u5668<\/td>\n<\/tr>\n<tr>\n<td>sse-meta<\/td>\n<td>SSE \u83dc\u5355\u4fe1\u606f\u884c<\/td>\n<\/tr>\n<tr>\n<td>ws-orders<\/td>\n<td>\u53f3\u4fa7 WS \u8ba2\u5355\u5361\u7247\u5bb9\u5668<\/td>\n<\/tr>\n<tr>\n<td>cmd<\/td>\n<td>\u547d\u4ee4\u8f93\u5165\u6846<\/td>\n<\/tr>\n<tr>\n<td>ws-log \/ ws-log-count<\/td>\n<td>\u901a\u4fe1\u65e5\u5fd7 \/ \u65e5\u5fd7\u6761\u6570<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u4e09\u4e2a\u6309\u94ae\u7528\u5185\u8054 onclick&#061;&#039;sendCmd({cmd:&#034;ping&#034;})&#039; \u76f4\u63a5\u8c03 JS \u51fd\u6570&#xff0c;\u7701\u4e8b\u3002<\/p>\n<h3>7.5 JS \u8bb2\u89e3&#xff08;\u6838\u5fc3\u903b\u8f91&#xff09;<\/h3>\n<h4>7.5.1 \u6e32\u67d3\u51fd\u6570 renderOrders<\/h4>\n<p><span class=\"token keyword\">const<\/span> <span class=\"token function-variable function\">renderOrders<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">el<span class=\"token punctuation\">,<\/span> list<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n  <span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token operator\">!<\/span>list <span class=\"token operator\">||<\/span> <span class=\"token operator\">!<\/span>list<span class=\"token punctuation\">.<\/span>length<span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span> el<span class=\"token punctuation\">.<\/span>innerHTML <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;&#8230;\u6682\u65e0\u8ba2\u5355&#8230;&#039;<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token function\">updateStats<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token keyword\">return<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n  el<span class=\"token punctuation\">.<\/span>innerHTML <span class=\"token operator\">&#061;<\/span> list<span class=\"token punctuation\">.<\/span><span class=\"token function\">map<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\">o<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">&#096;<\/span><span class=\"token string\"><br \/>\n    &lt;div class&#061;&#034;card <\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span><span class=\"token constant\">STATUS_CARD<\/span><span class=\"token punctuation\">[<\/span>o<span class=\"token punctuation\">.<\/span>status<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">||<\/span> <span class=\"token string\">&#039;&#039;<\/span><span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&#034;&gt;<br \/>\n      &lt;span class&#061;&#034;id&#034;&gt;#<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>id<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt;<br \/>\n      &lt;h3&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>drink<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/h3&gt;<br \/>\n      &#8230;<br \/>\n      &lt;div class&#061;&#034;bar&#034;&gt;&lt;div style&#061;&#034;width:<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>progress<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">%&#034;&gt;&lt;\/div&gt;&lt;\/div&gt;<br \/>\n      &lt;span class&#061;&#034;status <\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span><span class=\"token constant\">STATUS_CLASS<\/span><span class=\"token punctuation\">[<\/span>o<span class=\"token punctuation\">.<\/span>status<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">||<\/span> <span class=\"token string\">&#039;&#039;<\/span><span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&#034;&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>o<span class=\"token punctuation\">.<\/span>status<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt;<br \/>\n    &lt;\/div&gt;<br \/>\n  <\/span><span class=\"token template-punctuation string\">&#096;<\/span><\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">join<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token function\">updateStats<\/span><span class=\"token punctuation\">(<\/span>list<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/p>\n<ul>\n<li>\u63a5\u6536\u4e00\u4e2a DOM \u5143\u7d20\u548c\u8ba2\u5355\u6570\u7ec4&#xff0c;\u7528 map \u628a\u6bcf\u4e2a\u8ba2\u5355\u62fc\u6210\u5361\u7247 HTML \u5b57\u7b26\u4e32&#xff0c;\u6700\u540e join(&#039;&#039;) \u4e00\u6b21\u6027\u8d4b\u7ed9 innerHTML&#xff1b;<\/li>\n<li>STATUS_CLASS \/ STATUS_CARD \u662f\u72b6\u6001\u2192CSS \u7c7b\u7684\u6620\u5c04\u8868&#xff0c;\u7ed9\u5361\u7247\u52a0\u72b6\u6001\u8272&#xff1b;<\/li>\n<li>\u6bcf\u6b21\u6e32\u67d3\u90fd\u8c03 updateStats \u66f4\u65b0\u9876\u90e8\u7edf\u8ba1\u3002<\/li>\n<\/ul>\n<p>\u8fd9\u79cd\u300c\u6bcf\u6b21\u5168\u91cf\u91cd\u6e32\u67d3\u300d\u5bf9\u51e0\u5341\u4e2a\u8ba2\u5355\u5b8c\u5168\u6ca1\u95ee\u9898&#xff0c;\u7b80\u5355\u76f4\u63a5\u3002\u8ba2\u5355\u91cf\u5927\u65f6\u53ef\u6539\u6210 diff \u66f4\u65b0\u3002<\/p>\n<h4>7.5.2 SSE \u8fde\u63a5 connectSSE<\/h4>\n<p><span class=\"token keyword\">function<\/span> <span class=\"token function\">connectSSE<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n  <span class=\"token keyword\">const<\/span> es <span class=\"token operator\">&#061;<\/span> <span class=\"token keyword\">new<\/span> <span class=\"token class-name\">EventSource<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;\/sse\/orders&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  es<span class=\"token punctuation\">.<\/span><span class=\"token function\">addEventListener<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;hello&#039;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">e<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;sse-status&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;SSE: \u5df2\u8fde\u63a5&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;sse-dot&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>className <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;dot live&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> info <span class=\"token operator\">&#061;<\/span> <span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">parse<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>data<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;sse-meta&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;\u83dc\u5355: &#039;<\/span> <span class=\"token operator\">&#043;<\/span> info<span class=\"token punctuation\">.<\/span>menu<span class=\"token punctuation\">.<\/span><span class=\"token function\">join<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039; \/ &#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  es<span class=\"token punctuation\">.<\/span><span class=\"token function\">addEventListener<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;orders&#039;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">e<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> <span class=\"token punctuation\">{<\/span> time<span class=\"token punctuation\">,<\/span> orders <span class=\"token punctuation\">}<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">parse<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>data<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token function\">renderOrders<\/span><span class=\"token punctuation\">(<\/span>box<span class=\"token punctuation\">,<\/span> orders<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;clock&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token function\">fmtTime<\/span><span class=\"token punctuation\">(<\/span>time<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  es<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onerror<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;sse-status&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;SSE: \u65ad\u5f00, 3s \u540e\u91cd\u8fde&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;sse-dot&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>className <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;dot off&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    es<span class=\"token punctuation\">.<\/span><span class=\"token function\">close<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token function\">setTimeout<\/span><span class=\"token punctuation\">(<\/span>connectSSE<span class=\"token punctuation\">,<\/span> <span class=\"token number\">3000<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><br \/>\n<span class=\"token punctuation\">}<\/span><br \/>\n<span class=\"token function\">connectSSE<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><\/p>\n<ul>\n<li>new EventSource(&#039;\/sse\/orders&#039;)&#xff1a;\u5efa\u7acb SSE \u8fde\u63a5\u3002\u6d4f\u89c8\u5668\u81ea\u52a8\u5904\u7406\u91cd\u8fde&#xff0c;\u4f46\u8fd9\u91cc\u6211\u4eec\u624b\u52a8\u91cd\u8fde\u2014\u2014\u4e3a\u4e86\u80fd\u5728\u65ad\u5f00\u65f6\u66f4\u65b0\u72b6\u6001\u706f&#xff1b;<\/li>\n<li>addEventListener(&#039;hello&#039;, &#8230;)&#xff1a;\u76d1\u542c\u670d\u52a1\u5668\u53d1\u7684 hello \u4e8b\u4ef6&#xff08;event: hello \u5e27&#xff09;&#xff0c;\u6536\u5230\u5c31\u628a\u72b6\u6001\u706f\u53d8\u7eff\u3001\u663e\u793a\u83dc\u5355&#xff1b;<\/li>\n<li>addEventListener(&#039;orders&#039;, &#8230;)&#xff1a;\u76d1\u542c orders \u4e8b\u4ef6&#xff0c;\u6bcf\u6b21\u6536\u5230\u5c31\u6e32\u67d3\u8ba2\u5355\u5361\u7247 &#043; \u66f4\u65b0\u65f6\u949f&#xff1b;<\/li>\n<li>onerror&#xff1a;\u51fa\u9519\u65f6\u624b\u52a8 close &#043; 3 \u79d2\u540e\u91cd\u8fde&#xff0c;\u5e76\u628a\u72b6\u6001\u706f\u53d8\u7ea2\u3002<\/li>\n<\/ul>\n<p>\u6ce8\u610f&#xff1a;EventSource \u672c\u8eab\u6709\u81ea\u52a8\u91cd\u8fde&#xff0c;\u4f46\u914d\u5408\u624b\u52a8 close &#043; setTimeout \u80fd\u66f4\u597d\u63a7\u5236\u72b6\u6001\u663e\u793a\u3002\u8fd9\u91cc\u4e24\u8005\u7ed3\u5408\u3002<\/p>\n<h4>7.5.3 WS \u8fde\u63a5 connectWS<\/h4>\n<p><span class=\"token keyword\">function<\/span> <span class=\"token function\">connectWS<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n  <span class=\"token keyword\">const<\/span> proto <span class=\"token operator\">&#061;<\/span> location<span class=\"token punctuation\">.<\/span>protocol <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;https:&#039;<\/span> <span class=\"token operator\">?<\/span> <span class=\"token string\">&#039;wss&#039;<\/span> <span class=\"token operator\">:<\/span> <span class=\"token string\">&#039;ws&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token keyword\">const<\/span> ws <span class=\"token operator\">&#061;<\/span> <span class=\"token keyword\">new<\/span> <span class=\"token class-name\">WebSocket<\/span><span class=\"token punctuation\">(<\/span><span class=\"token template-string\"><span class=\"token template-punctuation string\">&#096;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>proto<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">:\/\/<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>location<span class=\"token punctuation\">.<\/span>host<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">\/ws\/orders<\/span><span class=\"token template-punctuation string\">&#096;<\/span><\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  ws<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onopen<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span> status<span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;WS: \u5df2\u8fde\u63a5&#039;<\/span><span class=\"token punctuation\">;<\/span> dot<span class=\"token punctuation\">.<\/span>className <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;dot live&#039;<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  ws<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onmessage<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">e<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n    <span class=\"token keyword\">const<\/span> msg <span class=\"token operator\">&#061;<\/span> <span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">parse<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>data<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token function\">wsLog<\/span><span class=\"token punctuation\">(<\/span>msg<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#039;in&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span>msg<span class=\"token punctuation\">.<\/span>type <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;hello&#039;<\/span> <span class=\"token operator\">||<\/span> msg<span class=\"token punctuation\">.<\/span>type <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;snapshot&#039;<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n      <span class=\"token function\">renderOrders<\/span><span class=\"token punctuation\">(<\/span>box<span class=\"token punctuation\">,<\/span> msg<span class=\"token punctuation\">.<\/span>orders <span class=\"token operator\">||<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n    <span class=\"token punctuation\">}<\/span><br \/>\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  ws<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onclose<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span> status<span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;WS: \u65ad\u5f00, 3s \u540e\u91cd\u8fde&#039;<\/span><span class=\"token punctuation\">;<\/span> dot<span class=\"token punctuation\">.<\/span>className <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#039;dot off&#039;<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token function\">setTimeout<\/span><span class=\"token punctuation\">(<\/span>connectWS<span class=\"token punctuation\">,<\/span> <span class=\"token number\">3000<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  window<span class=\"token punctuation\">.<\/span>_ws <span class=\"token operator\">&#061;<\/span> ws<span class=\"token punctuation\">;<\/span><br \/>\n<span class=\"token punctuation\">}<\/span><br \/>\n<span class=\"token function\">connectWS<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><\/p>\n<ul>\n<li>location.protocol \u5224\u65ad\u5f53\u524d\u662f http \u8fd8\u662f https&#xff0c;\u5bf9\u5e94\u7528 ws:\/\/ \u6216 wss:\/\/&#xff08;\u52a0\u5bc6&#xff09;&#xff1b;<\/li>\n<li>onopen&#xff1a;\u8fde\u4e0a\u540e\u72b6\u6001\u706f\u53d8\u7eff&#xff1b;<\/li>\n<li>onmessage&#xff1a;\u6bcf\u6536\u5230\u4e00\u6761\u6d88\u606f&#xff1a;\u2460 \u5199\u8fdb\u65e5\u5fd7 wsLog(msg, &#039;in&#039;)&#xff1b;\u2461 \u5982\u679c\u662f hello \u6216 snapshot&#xff08;\u5e26 orders&#xff09;&#xff0c;\u6e32\u67d3\u53f3\u4fa7\u8ba2\u5355\u5361\u7247&#xff1b;<\/li>\n<li>onclose&#xff1a;WebSocket \u4e0d\u81ea\u52a8\u91cd\u8fde&#xff0c;\u5fc5\u987b\u81ea\u5df1\u5904\u7406\u2014\u20143 \u79d2\u540e\u91cd\u8fde&#xff1b;<\/li>\n<li>window._ws &#061; ws&#xff1a;\u628a\u8fde\u63a5\u5bf9\u8c61\u5b58\u5230\u5168\u5c40&#xff0c;sendCmd \u51fd\u6570\u8981\u7528\u3002<\/li>\n<\/ul>\n<p>\u4e3a\u4ec0\u4e48 onmessage \u91cc\u53ea\u5904\u7406 hello\/snapshot&#xff1f;\u56e0\u4e3a\u5e7f\u64ad\u5668\u63a8\u7684\u8ba2\u5355\u66f4\u65b0&#xff08;\u6bcf 0.8s&#xff09;\u6ca1\u6709 type \u5b57\u6bb5&#xff08;\u7eaf\u5feb\u7167&#xff09;&#xff0c;\u53f3\u4fa7\u8ba2\u5355\u5361\u7247\u4e3b\u8981\u9760 hello \u521d\u59cb\u6e32\u67d3 &#043; \u547d\u4ee4\u56de\u6267\u5237\u65b0\u3002\u8ba2\u5355\u7684\u5b9e\u65f6\u66f4\u65b0\u7531\u5de6\u4fa7 SSE \u8d1f\u8d23&#xff0c;\u53f3\u4fa7 WS \u4fa7\u91cd\u5c55\u793a\u300c\u547d\u4ee4\u4ea4\u4e92\u300d\u3002\u8fd9\u662f\u9879\u76ee\u7684\u5206\u5de5\u8bbe\u8ba1\u3002<\/p>\n<h4>7.5.4 \u53d1\u547d\u4ee4 sendCmd &#043; \u65e5\u5fd7 wsLog<\/h4>\n<p><span class=\"token keyword\">function<\/span> <span class=\"token function\">sendCmd<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\">obj<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n  <span class=\"token keyword\">const<\/span> ws <span class=\"token operator\">&#061;<\/span> window<span class=\"token punctuation\">.<\/span>_ws<span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token operator\">!<\/span>ws <span class=\"token operator\">||<\/span> ws<span class=\"token punctuation\">.<\/span>readyState <span class=\"token operator\">!&#061;&#061;<\/span> <span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">return<\/span><span class=\"token punctuation\">;<\/span>   <span class=\"token comment\">\/\/ 1 &#061; OPEN<\/span><br \/>\n  ws<span class=\"token punctuation\">.<\/span><span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span>obj<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token function\">wsLog<\/span><span class=\"token punctuation\">(<\/span>obj<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#039;out&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n<span class=\"token punctuation\">}<\/span><\/p>\n<ul>\n<li>\u6309\u94ae\u70b9\u51fb\u6216\u8f93\u5165\u6846\u56de\u8f66\u65f6\u8c03\u7528&#xff1b;<\/li>\n<li>ws.readyState !&#061;&#061; 1&#xff1a;\u8fde\u63a5\u4e0d\u662f OPEN \u72b6\u6001\u5c31\u5ffd\u7565&#xff08;\u9632\u6b62\u6ca1\u8fde\u4e0a\u65f6\u53d1&#xff09;&#xff1b;<\/li>\n<li>\u53d1\u9001\u540e\u628a\u547d\u4ee4\u4e5f\u5199\u8fdb\u65e5\u5fd7&#xff08;dir&#061;&#039;out&#039;&#xff0c;\u7528 \u2192 \u7bad\u5934&#xff09;\u3002<\/li>\n<\/ul>\n<p><span class=\"token keyword\">const<\/span> <span class=\"token function-variable function\">wsLog<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">m<span class=\"token punctuation\">,<\/span> dir<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n  <span class=\"token keyword\">const<\/span> line <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token keyword\">typeof<\/span> m <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;string&#039;<\/span> <span class=\"token operator\">?<\/span> m <span class=\"token operator\">:<\/span> <span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span>m<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token keyword\">const<\/span> arrow <span class=\"token operator\">&#061;<\/span> dir <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;out&#039;<\/span> <span class=\"token operator\">?<\/span> <span class=\"token string\">&#039;&lt;span class&#061;&#034;arrow-out&#034;&gt;\u2192&lt;\/span&gt;&#039;<\/span> <span class=\"token operator\">:<\/span> <span class=\"token string\">&#039;&lt;span class&#061;&#034;arrow-in&#034;&gt;\u2190&lt;\/span&gt;&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  <span class=\"token keyword\">const<\/span> colored <span class=\"token operator\">&#061;<\/span> line<span class=\"token punctuation\">.<\/span><span class=\"token function\">replace<\/span><span class=\"token punctuation\">(<\/span><span class=\"token regex\"><span class=\"token regex-delimiter\">\/<\/span><span class=\"token regex-source language-regex\">&#034;type&#034;:&#034;([^&#034;]&#043;)&#034;<\/span><span class=\"token regex-delimiter\">\/<\/span><span class=\"token regex-flags\">g<\/span><\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#039;&#034;type&#034;:&#034;&lt;span class&#061;&#034;type&#034;&gt;$1&lt;\/span&gt;&#034;&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  log<span class=\"token punctuation\">.<\/span>innerHTML <span class=\"token operator\">&#061;<\/span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">&#096;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>arrow<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\"> <\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>colored<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">\\\\n<\/span><span class=\"token template-punctuation string\">&#096;<\/span><\/span> <span class=\"token operator\">&#043;<\/span> log<span class=\"token punctuation\">.<\/span>innerHTML<span class=\"token punctuation\">.<\/span><span class=\"token function\">split<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;\\\\n&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">slice<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">40<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">join<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;\\\\n&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  logCount<span class=\"token operator\">&#043;&#043;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n  document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;ws-log-count&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>textContent <span class=\"token operator\">&#061;<\/span> logCount <span class=\"token operator\">&#043;<\/span> <span class=\"token string\">&#039; \u6761&#039;<\/span><span class=\"token punctuation\">;<\/span><br \/>\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/p>\n<ul>\n<li>\u628a\u6d88\u606f\u683c\u5f0f\u5316\u6210\u4e00\u884c&#xff0c;\u524d\u9762\u52a0\u7bad\u5934&#xff08;\u2192 \u53d1\u51fa \/ \u2190 \u6536\u5230&#xff09;&#xff1b;<\/li>\n<li>\u7528\u6b63\u5219\u628a &#034;type&#034;:&#034;xxx&#034; \u91cc\u7684 xxx \u9ad8\u4eae\u6210\u84dd\u8272&#xff0c;\u65b9\u4fbf\u770b\u6d88\u606f\u7c7b\u578b&#xff1b;<\/li>\n<li>\u65b0\u65e5\u5fd7\u63d2\u5728\u6700\u4e0a\u9762&#xff0c;\u6700\u591a\u4fdd\u7559 40 \u884c&#xff08;slice(0, 40)&#xff09;&#xff0c;\u9632\u6b62\u65e0\u9650\u589e\u957f&#xff1b;<\/li>\n<li>\u66f4\u65b0\u65e5\u5fd7\u6761\u6570\u8ba1\u6570\u3002<\/li>\n<\/ul>\n<h4>7.5.5 \u8f93\u5165\u6846\u56de\u8f66\u53d1\u547d\u4ee4<\/h4>\n<p>document<span class=\"token punctuation\">.<\/span><span class=\"token function\">getElementById<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;cmd&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">addEventListener<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;keydown&#039;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\">e<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n  <span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>key <span class=\"token operator\">&#061;&#061;&#061;<\/span> <span class=\"token string\">&#039;Enter&#039;<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token keyword\">try<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token function\">sendCmd<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">parse<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>target<span class=\"token punctuation\">.<\/span>value<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span> <span class=\"token punctuation\">}<\/span> <span class=\"token keyword\">catch<\/span> <span class=\"token punctuation\">(<\/span>_<span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">}<\/span> <span class=\"token punctuation\">}<\/span><br \/>\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><\/p>\n<ul>\n<li>\u5728\u8f93\u5165\u6846\u91cc\u6572 {&#034;cmd&#034;:&#034;pickup&#034;,&#034;arg&#034;:3} \u7136\u540e\u56de\u8f66&#xff0c;\u4f1a JSON.parse \u540e\u53d1\u9001&#xff1b;<\/li>\n<li>try\/catch \u9632\u6b62 JSON \u683c\u5f0f\u9519\u65f6\u9875\u9762\u62a5\u9519&#xff08;\u9759\u9ed8\u5ffd\u7565&#xff09;\u3002<\/li>\n<\/ul>\n<h3>7.6 SSE \u4e0e WS \u5728\u524d\u7aef\u7684\u5206\u5de5<\/h3>\n<table>\n<tr>\u529f\u80fd\u7528\u8c01\u4e3a\u4ec0\u4e48<\/tr>\n<tbody>\n<tr>\n<td>\u5b9e\u65f6\u8ba2\u5355\u5237\u65b0&#xff08;\u6bcf 0.8s&#xff09;<\/td>\n<td>SSE<\/td>\n<td>\u5355\u5411\u63a8\u9001&#xff0c;\u6700\u7b80\u5355<\/td>\n<\/tr>\n<tr>\n<td>\u5b9e\u65f6\u65f6\u949f<\/td>\n<td>SSE&#xff08;orders \u5e27\u5e26 time&#xff09;<\/td>\n<td>\u987a\u5e26<\/td>\n<\/tr>\n<tr>\n<td>\u83dc\u5355\u663e\u793a<\/td>\n<td>SSE&#xff08;hello&#xff09;&#043; WS&#xff08;hello&#xff09;<\/td>\n<td>\u4e24\u8fb9\u5404\u81ea\u5c55\u793a<\/td>\n<\/tr>\n<tr>\n<td>ping \/ add \/ pickup \/ snapshot<\/td>\n<td>WS<\/td>\n<td>\u9700\u8981\u53cc\u5411<\/td>\n<\/tr>\n<tr>\n<td>\u901a\u4fe1\u65e5\u5fd7\u5c55\u793a<\/td>\n<td>WS<\/td>\n<td>\u5c55\u793a WS \u7684\u6536\u53d1<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>7.7 \u52a8\u624b\u9a8c\u8bc1<\/h3>\n<p>\u5199\u5b8c index.html&#xff0c;\u542f\u52a8\u670d\u52a1&#xff08;\u7b2c 6 \u7ae0\u7684\u547d\u4ee4&#xff09;&#xff0c;\u6d4f\u89c8\u5668\u6253\u5f00 http:\/\/127.0.0.1:8000\/&#xff1a;<\/p>\n<ul>\n<li>\u9876\u90e8 SSE \/ WS \u72b6\u6001\u706f\u5e94\u5728 1 \u79d2\u5185\u53d8\u7eff\u3001\u65f6\u949f\u5f00\u59cb\u8d70&#xff1b;<\/li>\n<li>\u5de6\u4fa7\u300c\u5b9e\u65f6\u8ba2\u5355\u300d\u6bcf 0.8s \u5237\u65b0&#xff0c;\u8ba2\u5355\u5361\u7247\u8d8a\u6765\u8d8a\u591a\u3001\u8fdb\u5ea6\u6761\u5728\u6da8&#xff1b;<\/li>\n<li>\u70b9\u53f3\u4fa7 &#x1f4e1; ping&#xff1a;\u65e5\u5fd7\u51fa\u73b0 \u2192 {cmd:ping} \u548c \u2190 {type:pong,&#8230;}&#xff1b;<\/li>\n<li>\u70b9 \u2795 \u52a0\u5355&#xff1a;\u65e5\u5fd7\u51fa\u73b0 \u2192 {cmd:add} \u548c \u2190 {type:added,&#8230;}&#xff0c;\u53f3\u4fa7\u8ba2\u5355\u5217\u8868\u591a\u4e00\u5f20\u5361&#xff1b;<\/li>\n<li>\u70b9 &#x1f4f8; snapshot&#xff1a;\u65e5\u5fd7\u51fa\u73b0 \u2192 {cmd:snapshot} \u548c \u2190 {type:snapshot,&#8230;}&#xff0c;\u53f3\u4fa7\u8ba2\u5355\u5237\u65b0&#xff1b;<\/li>\n<li>\u5728\u8f93\u5165\u6846\u6572 {&#034;cmd&#034;:&#034;pickup&#034;,&#034;arg&#034;:&lt;\u67d0\u4e2a\u5df2\u5b8c\u6210\u7684id&gt;} \u56de\u8f66&#xff1a;\u8be5\u8ba2\u5355\u53d8\u6210\u300c\u5df2\u53d6\u9910\u300d\u3002<\/li>\n<\/ul>\n<p>\u5b8c\u6574\u6548\u679c\u622a\u56fe\u89c1 08-\u8fd0\u884c\u4e0e\u9a8c\u8bc1.md\u3002<\/p>\n<hr \/>\n<p>\u4e0b\u4e00\u7ae0 \u2192 08-\u8fd0\u884c\u4e0e\u9a8c\u8bc1.md&#xff1a;\u5b8c\u6574\u8fd0\u884c\u6b65\u9aa4 &#043; \u9a8c\u8bc1\u6e05\u5355 &#043; \u8fd0\u884c\u622a\u56fe &#043; \u5e38\u89c1\u95ee\u9898\u3002<\/p>\n<hr \/>\n<h2>\u7b2c 8 \u7ae0 \u00b7 \u8fd0\u884c\u4e0e\u9a8c\u8bc1<\/h2>\n<h3>\u672c\u7ae0\u76ee\u6807<\/h3>\n<p>\u628a\u6240\u6709\u6587\u4ef6\u7ec4\u88c5\u597d\u3001\u542f\u52a8\u670d\u52a1\u3001\u9010\u4e00\u9a8c\u8bc1\u529f\u80fd\u3002\u672c\u7ae0\u7ed9\u51fa&#xff1a;<\/p>\n<ul>\n<li>\u5b8c\u6574\u8fd0\u884c\u6b65\u9aa4&#xff08;\u4e24\u79cd\u542f\u52a8\u65b9\u5f0f&#xff09;&#xff1b;<\/li>\n<li>\u542f\u52a8\u540e\u5e94\u770b\u5230\u4ec0\u4e48&#xff08;\u542b\u9879\u76ee\u8fd0\u884c\u622a\u56fe&#xff09;&#xff1b;<\/li>\n<li>\u529f\u80fd\u9a8c\u8bc1\u6e05\u5355&#xff08;\u9010\u6761\u52fe\u9009&#xff09;&#xff1b;<\/li>\n<li>\u5e38\u89c1\u95ee\u9898\u4e0e\u89e3\u51b3\u529e\u6cd5\u3002<\/li>\n<\/ul>\n<p>\u5047\u8bbe\u4f60\u5df2\u7ecf\u6309\u7b2c 1&#xff5e;7 \u7ae0\u987a\u5e8f\u5199\u5b8c\u6240\u6709\u6587\u4ef6\u3002\u5f53\u524d\u76ee\u5f55\u7ed3\u6784\u5e94\u662f&#xff1a;<\/p>\n<p> fastapi-sse-ws-\u5976\u8336\u770b\u677f\/<br \/>\n\u251c\u2500\u2500 pyproject.toml  .python-version  .gitignore  uv.lock<br \/>\n\u251c\u2500\u2500 src\/  __init__.py  app.py  broadcaster.py  models.py  sse.py  ws.py<br \/>\n\u2514\u2500\u2500 static\/  index.html<\/p>\n<hr \/>\n<h3>8.1 \u542f\u52a8\u670d\u52a1<\/h3>\n<h4>\u65b9\u5f0f A&#xff1a;\u547d\u4ee4\u884c&#xff08;\u63a8\u8350&#xff09;<\/h4>\n<p>\u5728\u9879\u76ee\u6839\u76ee\u5f55\u6267\u884c&#xff1a;<\/p>\n<p>uv run python <span class=\"token parameter variable\">-m<\/span> uvicorn src.app:app <span class=\"token parameter variable\">&#8211;host<\/span> <span class=\"token number\">127.0<\/span>.0.1 <span class=\"token parameter variable\">&#8211;port<\/span> <span class=\"token number\">8000<\/span> <span class=\"token parameter variable\">&#8211;reload<\/span><\/p>\n<p>\u7528 pip \u7684\u8bdd&#xff08;\u5148 pip install fastapi &#034;uvicorn[standard]&#034; websockets&#xff09;&#xff1a;<\/p>\n<p> python <span class=\"token parameter variable\">-m<\/span> uvicorn src.app:app <span class=\"token parameter variable\">&#8211;host<\/span> <span class=\"token number\">127.0<\/span>.0.1 <span class=\"token parameter variable\">&#8211;port<\/span> <span class=\"token number\">8000<\/span> <span class=\"token parameter variable\">&#8211;reload<\/span><\/p>\n<p>\u542f\u52a8\u6210\u529f\u7684\u7ec8\u7aef\u8f93\u51fa&#xff1a;<\/p>\n<p>INFO:     Will watch for changes in these directories: [&#039;&#8230;\u9879\u76ee\u6839&#039;]<br \/>\nINFO:     Uvicorn running on http:\/\/127.0.0.1:8000 (Press CTRL&#043;C to quit)<br \/>\nINFO:     Started reloader process [xxxx] using StatReload<br \/>\nINFO:     Started server process [xxxx]<br \/>\nINFO:     Waiting for application startup.<br \/>\nINFO:     Application startup complete.<\/p>\n<ul>\n<li>Application startup complete. \u8868\u793a lifespan \u542f\u52a8\u9636\u6bb5\u8dd1\u5b8c\u4e86&#xff0c;\u5e7f\u64ad\u5668\u5df2\u5728\u540e\u53f0\u8fd0\u884c&#xff1b;<\/li>\n<li>&#8211;reload \u8ba9\u4f60\u6539\u4ee3\u7801\u540e\u81ea\u52a8\u91cd\u542f&#xff0c;\u5f00\u53d1\u65f6\u5f88\u65b9\u4fbf&#xff1b;<\/li>\n<li>\u4e0d\u8981\u5173\u95ed\u8fd9\u4e2a\u7ec8\u7aef&#xff0c;\u670d\u52a1\u8981\u4e00\u76f4\u8dd1\u3002\u6309 Ctrl&#043;C \u505c\u6b62\u3002<\/li>\n<\/ul>\n<h4>\u65b9\u5f0f B&#xff1a;\u76f4\u63a5\u8fd0\u884c app.py<\/h4>\n<p>\u56e0\u4e3a app.py \u672b\u5c3e\u6709 if __name__ &#061;&#061; &#034;__main__&#034;&#xff1a;<\/p>\n<p>uv run python src\/app.py<\/p>\n<p>\u6548\u679c\u548c\u65b9\u5f0f A \u4e00\u6837&#xff0c;\u4f46 reload \u53ea\u5728 app.py \u6539\u52a8\u65f6\u89e6\u53d1&#xff08;\u5176\u4ed6\u6587\u4ef6\u6539\u52a8\u4e0d\u4f1a&#xff09;&#xff0c;\u5f00\u53d1\u65f6\u4e0d\u5982\u65b9\u5f0f A \u65b9\u4fbf\u3002<\/p>\n<hr \/>\n<h3>8.2 \u6253\u5f00\u6d4f\u89c8\u5668\u770b\u6548\u679c<\/h3>\n<p>\u6d4f\u89c8\u5668\u8bbf\u95ee http:\/\/127.0.0.1:8000\/\u3002<\/p>\n<p>\u51e0\u79d2\u5185\u4f60\u5e94\u8be5\u770b\u5230&#xff1a;<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/08\/20260804081737-6a71a021780c1.png\" alt=\"\u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f\u8fd0\u884c\u622a\u56fe\" \/><\/p>\n<p>\u9010\u9879\u786e\u8ba4&#xff1a;<\/p>\n<ul>\n<li>\u9876\u90e8\u5bfc\u822a&#xff1a;\u6807\u9898\u300c&#x1f9cb; \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f\u300d&#043; \u53f3\u4fa7\u4e09\u4e2a\u80f6\u56ca&#xff1a;\n<ul>\n<li>SSE: \u5df2\u8fde\u63a5&#xff08;\u7eff\u70b9\u95ea\u70c1&#xff09;<\/li>\n<li>WS: \u5df2\u8fde\u63a5&#xff08;\u7eff\u70b9\u95ea\u70c1&#xff09;<\/li>\n<li>\u5b9e\u65f6\u65f6\u949f HH:MM:SS&#xff08;\u6bcf 0.8s \u8df3\u4e00\u6b21&#xff09;&#xff1b;<\/li>\n<\/ul>\n<\/li>\n<li>\u7edf\u8ba1\u6761&#xff1a;4 \u4e2a\u6570\u5b57\u5361\u7247&#xff08;\u603b\u8ba2\u5355 \/ \u5236\u4f5c\u4e2d \/ \u5df2\u5b8c\u6210 \/ \u5df2\u53d6\u9910&#xff09;&#xff0c;\u6570\u5b57\u4f1a\u968f\u8ba2\u5355\u53d8\u5316&#xff1b;<\/li>\n<li>\u5de6\u4fa7\u300c&#x1f4cb; \u5b9e\u65f6\u8ba2\u5355\u300d&#xff08;\u6807\u7b7e\u300cSSE \u5355\u5411\u63a8\u9001\u300d&#xff09;&#xff1a;\u8ba2\u5355\u5361\u7247\u7f51\u683c&#xff0c;\u6bcf\u5f20\u5361\u663e\u793a\u996e\u54c1\u540d\u3001\u8336\u5e95\/\u7cd6\u5ea6\/\u51b0\u5ea6\/\u52a0\u6599\/\u4ef7\u683c\u3001\u8fdb\u5ea6\u6761\u3001\u72b6\u6001\u6807\u7b7e\u3001\u4e0b\u5355\u65f6\u95f4\u3002\u6bcf 0.8s \u6574\u4f53\u5237\u65b0\u4e00\u6b21&#xff1b;<\/li>\n<li>\u53f3\u4fa7\u300c&#x1f39b;\ufe0f \u5e97\u5458\u64cd\u4f5c\u53f0\u300d&#xff08;\u6807\u7b7e\u300cWebSocket \u53cc\u5411\u901a\u9053\u300d&#xff09;&#xff1a;\u4e0a\u65b9\u540c\u6837\u8ba2\u5355\u5361\u7247&#xff1b;\u4e0b\u65b9\u547d\u4ee4\u8f93\u5165\u6846\u30013 \u4e2a\u6309\u94ae\u3001\u9ed1\u5e95\u901a\u4fe1\u65e5\u5fd7\u533a\u3002<\/li>\n<\/ul>\n<h3>8.3 \u64cd\u4f5c WebSocket \u53cc\u5411\u901a\u9053<\/h3>\n<p>\u5728\u53f3\u4fa7\u64cd\u4f5c\u53f0\u505a\u4ee5\u4e0b\u64cd\u4f5c&#xff0c;\u89c2\u5bdf\u901a\u4fe1\u65e5\u5fd7\u548c\u8ba2\u5355\u53d8\u5316&#xff1a;<\/p>\n<h4>\u2460 \u70b9 &#x1f4e1; ping<\/h4>\n<ul>\n<li>\u65e5\u5fd7\u51fa\u73b0\u4e24\u884c&#xff1a;\n<ul>\n<li>\u2192 {&#034;cmd&#034;:&#034;ping&#034;}&#xff08;\u6a59\u8272\u7bad\u5934&#xff0c;\u8868\u793a\u53d1\u51fa&#xff09;<\/li>\n<li>\u2190 {&#034;type&#034;:&#034;pong&#034;,&#034;time&#034;:&#034;&#8230;&#034;}&#xff08;\u7eff\u8272\u7bad\u5934&#xff0c;\u8868\u793a\u6536\u5230&#xff09;&#xff1b;<\/li>\n<\/ul>\n<\/li>\n<li>\u8ba2\u5355\u65e0\u53d8\u5316\u3002ping \u7eaf\u63a2\u6d3b\u3002<\/li>\n<\/ul>\n<h4>\u2461 \u70b9 \u2795 \u52a0\u5355<\/h4>\n<ul>\n<li>\u65e5\u5fd7\u51fa\u73b0&#xff1a;\n<ul>\n<li>\u2192 {&#034;cmd&#034;:&#034;add&#034;}<\/li>\n<li>\u2190 {&#034;type&#034;:&#034;added&#034;,&#034;order&#034;:{&#034;id&#034;:N,&#034;drink&#034;:&#034;&#8230;&#034;,&#034;status&#034;:&#034;\u5f85\u5236\u4f5c&#034;,&#034;progress&#034;:0,&#8230;}}&#xff1b;<\/li>\n<\/ul>\n<\/li>\n<li>\u53f3\u4fa7\u8ba2\u5355\u5217\u8868\u7acb\u523b\u591a\u4e00\u5f20\u300c\u5f85\u5236\u4f5c\u300d\u5361\u7247&#xff1b;<\/li>\n<li>\u5de6\u4fa7 SSE \u770b\u677f\u4f1a\u5728\u4e0b\u4e00\u6b21\u5e7f\u64ad&#xff08;\u6700\u591a 0.8s \u540e&#xff09;\u4e5f\u51fa\u73b0\u8fd9\u5f20\u65b0\u5355\u3002<\/li>\n<\/ul>\n<h4>\u2462 \u70b9 &#x1f4f8; snapshot<\/h4>\n<ul>\n<li>\u65e5\u5fd7\u51fa\u73b0&#xff1a;\n<ul>\n<li>\u2192 {&#034;cmd&#034;:&#034;snapshot&#034;}<\/li>\n<li>\u2190 {&#034;type&#034;:&#034;snapshot&#034;,&#034;time&#034;:&#034;&#8230;&#034;,&#034;orders&#034;:[&#8230;]}&#xff1b;<\/li>\n<\/ul>\n<\/li>\n<li>\u53f3\u4fa7\u8ba2\u5355\u5361\u7247\u6574\u4f53\u5237\u65b0&#xff08;\u62c9\u4e00\u6b21\u5168\u91cf\u5feb\u7167&#xff09;\u3002<\/li>\n<\/ul>\n<h4>\u2463 \u7528\u8f93\u5165\u6846 pickup \u53d6\u9910<\/h4>\n<p>\u5728\u547d\u4ee4\u8f93\u5165\u6846\u91cc\u6572&#xff08;\u628a 3 \u6362\u6210\u67d0\u4e2a\u300c\u5df2\u5b8c\u6210\u300d\u8ba2\u5355\u7684 id&#xff09;&#xff1a;<\/p>\n<p>{&#034;cmd&#034;:&#034;pickup&#034;,&#034;arg&#034;:3}<\/p>\n<p>\u6309\u56de\u8f66\u3002<\/p>\n<ul>\n<li>\u5982\u679c id \u5bf9\u5e94\u8ba2\u5355\u662f\u300c\u5df2\u5b8c\u6210\u300d&#xff1a;\n<ul>\n<li>\u65e5\u5fd7&#xff1a;\u2192 {&#034;cmd&#034;:&#034;pickup&#034;,&#034;arg&#034;:3} \u548c \u2190 {&#034;type&#034;:&#034;picked&#034;,&#034;order&#034;:{&#8230;,&#034;status&#034;:&#034;\u5df2\u53d6\u9910&#034;}}&#xff1b;<\/li>\n<li>\u8be5\u8ba2\u5355\u5361\u7247\u72b6\u6001\u53d8\u6210\u300c\u5df2\u53d6\u9910\u300d&#xff08;\u5de6\u4fa7\u8272\u6761\u53d8\u7070&#xff09;&#xff1b;<\/li>\n<\/ul>\n<\/li>\n<li>\u5982\u679c\u8ba2\u5355\u4e0d\u5b58\u5728\u6216\u8fd8\u6ca1\u300c\u5df2\u5b8c\u6210\u300d&#xff1a;\n<ul>\n<li>\u65e5\u5fd7&#xff1a;\u2190 {&#034;type&#034;:&#034;error&#034;,&#034;error&#034;:&#034;order 3 not found&#034;} \u6216 \u2190 {&#034;type&#034;:&#034;error&#034;,&#034;error&#034;:&#034;order 3 not ready&#034;}&#xff1b;<\/li>\n<\/ul>\n<\/li>\n<li>\u5982\u679c arg \u4e0d\u662f\u6570\u5b57&#xff1a;\n<ul>\n<li>\u65e5\u5fd7&#xff1a;\u2190 {&#034;type&#034;:&#034;error&#034;,&#034;error&#034;:&#034;arg must be int order_id&#034;}\u3002<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u64cd\u4f5c\u51e0\u6b21\u540e&#xff0c;\u65e5\u5fd7\u533a\u4f1a\u50cf\u8fd9\u6837&#xff1a;<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/08\/20260804081737-6a71a021e51d4.png\" alt=\"WebSocket \u64cd\u4f5c\u53f0\u4e0e\u901a\u4fe1\u65e5\u5fd7\" \/><\/p>\n<p>\u6ce8\u610f\u65e5\u5fd7\u91cc type \u5b57\u6bb5\u662f\u9ad8\u4eae\u84dd\u8272\u7684&#xff0c;\u65b9\u4fbf\u8fa8\u8ba4\u6d88\u606f\u7c7b\u578b&#xff1b;\u7bad\u5934\u989c\u8272\u533a\u5206\u6536\u53d1\u65b9\u5411\u3002<\/p>\n<h3>8.4 \u9a8c\u8bc1\u6e05\u5355&#xff08;\u9010\u6761\u52fe\u9009&#xff09;<\/h3>\n<table>\n<tr>#\u9a8c\u8bc1\u9879\u671f\u671b<\/tr>\n<tbody>\n<tr>\n<td>1<\/td>\n<td>\u542f\u52a8\u4e0d\u62a5\u9519<\/td>\n<td>\u770b\u5230 Application startup complete.<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>\u6d4f\u89c8\u5668\u6253\u5f00 \/<\/td>\n<td>\u663e\u793a\u770b\u677f&#xff0c;\u4e0d\u662f 404<\/td>\n<\/tr>\n<tr>\n<td>3<\/td>\n<td>SSE \u72b6\u6001\u706f<\/td>\n<td>1 \u79d2\u5185\u53d8\u7eff\u95ea\u70c1<\/td>\n<\/tr>\n<tr>\n<td>4<\/td>\n<td>WS \u72b6\u6001\u706f<\/td>\n<td>1 \u79d2\u5185\u53d8\u7eff\u95ea\u70c1<\/td>\n<\/tr>\n<tr>\n<td>5<\/td>\n<td>\u65f6\u949f<\/td>\n<td>\u6bcf 0.8s \u8d70\u4e00\u6b21<\/td>\n<\/tr>\n<tr>\n<td>6<\/td>\n<td>\u5de6\u4fa7\u8ba2\u5355<\/td>\n<td>\u81ea\u52a8\u51fa\u73b0\u5e76\u63a8\u8fdb&#xff08;\u5f85\u5236\u4f5c\u2192\u5236\u4f5c\u4e2d\u2192\u5df2\u5b8c\u6210\u2192\u5df2\u53d6\u9910&#xff09;<\/td>\n<\/tr>\n<tr>\n<td>7<\/td>\n<td>\u8fdb\u5ea6\u6761<\/td>\n<td>\u300c\u5236\u4f5c\u4e2d\u300d\u8ba2\u5355\u8fdb\u5ea6\u6761\u5e73\u6ed1\u589e\u957f<\/td>\n<\/tr>\n<tr>\n<td>8<\/td>\n<td>\u8001\u300c\u5df2\u53d6\u9910\u300d\u8ba2\u5355<\/td>\n<td>\u6ee1\u4e00\u5b9a\u6570\u91cf\u540e\u4ece\u770b\u677f\u6d88\u5931&#xff08;\u961f\u5217\u53ea\u7559 8 \u6761&#xff09;<\/td>\n<\/tr>\n<tr>\n<td>9<\/td>\n<td>ping \u6309\u94ae<\/td>\n<td>\u65e5\u5fd7\u51fa\u73b0 pong \u56de\u6267<\/td>\n<\/tr>\n<tr>\n<td>10<\/td>\n<td>add \u6309\u94ae<\/td>\n<td>\u7acb\u523b\u591a\u4e00\u5f20\u8ba2\u5355\u5361<\/td>\n<\/tr>\n<tr>\n<td>11<\/td>\n<td>snapshot \u6309\u94ae<\/td>\n<td>\u53f3\u4fa7\u8ba2\u5355\u5237\u65b0<\/td>\n<\/tr>\n<tr>\n<td>12<\/td>\n<td>pickup \u5408\u6cd5 id<\/td>\n<td>\u8ba2\u5355\u53d8\u300c\u5df2\u53d6\u9910\u300d<\/td>\n<\/tr>\n<tr>\n<td>13<\/td>\n<td>pickup \u975e\u6cd5 id<\/td>\n<td>\u65e5\u5fd7\u51fa\u73b0 error \u56de\u6267<\/td>\n<\/tr>\n<tr>\n<td>14<\/td>\n<td>\u8f93\u5165\u6846\u975e\u6cd5 JSON<\/td>\n<td>\u9759\u9ed8\u5ffd\u7565&#xff0c;\u4e0d\u62a5\u9519<\/td>\n<\/tr>\n<tr>\n<td>15<\/td>\n<td>\u5173\u6389\u6d4f\u89c8\u5668\u518d\u5f00<\/td>\n<td>SSE\/WS \u81ea\u52a8\u91cd\u8fde&#xff0c;\u72b6\u6001\u706f\u91cd\u65b0\u53d8\u7eff<\/td>\n<\/tr>\n<tr>\n<td>16<\/td>\n<td>\u6539\u4efb\u610f\u540e\u7aef\u6587\u4ef6<\/td>\n<td>uvicorn \u81ea\u52a8\u91cd\u542f&#xff08;&#8211;reload&#xff09;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u5168\u90e8\u901a\u8fc7 &#061; \u9879\u76ee\u5b8c\u6574\u8dd1\u901a &#x1f389;<\/p>\n<h3>8.5 \u7528 curl \u9a8c\u8bc1 SSE&#xff08;\u65e0\u9700\u6d4f\u89c8\u5668&#xff09;<\/h3>\n<p>\u53e6\u5f00\u4e00\u4e2a\u7ec8\u7aef&#xff1a;<\/p>\n<p><span class=\"token function\">curl<\/span> <span class=\"token parameter variable\">-N<\/span> http:\/\/127.0.0.1:8000\/sse\/orders<\/p>\n<ul>\n<li>-N&#xff1a;&#8211;no-buffer&#xff0c;\u7981\u7528\u7f13\u51b2&#xff0c;\u5b9e\u65f6\u8f93\u51fa&#xff1b;<\/li>\n<li>\u4f60\u4f1a\u6301\u7eed\u770b\u5230 event: hello \u548c event: orders \u5e27\u6d41\u5f0f\u8f93\u51fa&#xff0c;\u6bcf 0.8s \u4e00\u5e27&#xff1b;<\/li>\n<li>\u6309 Ctrl&#043;C \u9000\u51fa\u3002<\/li>\n<\/ul>\n<h3>8.6 \u7528\u6d4f\u89c8\u5668\u63a7\u5236\u53f0\u9a8c\u8bc1 WS<\/h3>\n<p>\u5728 http:\/\/127.0.0.1:8000\/ \u9875\u9762\u6309 F12 \u6253\u5f00\u63a7\u5236\u53f0&#xff0c;\u6267\u884c&#xff1a;<\/p>\n<p><span class=\"token keyword\">const<\/span> ws <span class=\"token operator\">&#061;<\/span> <span class=\"token keyword\">new<\/span> <span class=\"token class-name\">WebSocket<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;ws:\/\/127.0.0.1:8000\/ws\/orders&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onmessage<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token parameter\">e<\/span> <span class=\"token operator\">&#061;&gt;<\/span> console<span class=\"token punctuation\">.<\/span><span class=\"token function\">log<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">parse<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>data<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onopen<\/span>  <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> console<span class=\"token punctuation\">.<\/span><span class=\"token function\">log<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u5df2\u8fde\u63a5&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function-variable function\">onclose<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&gt;<\/span> console<span class=\"token punctuation\">.<\/span><span class=\"token function\">log<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u5df2\u65ad\u5f00&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><\/p>\n<p><span class=\"token comment\">\/\/ \u7b49\u300c\u5df2\u8fde\u63a5\u300d\u51fa\u73b0\u540e:<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">cmd<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">&#034;ping&#034;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>       <span class=\"token comment\">\/\/ \u770b\u5230 {type:&#034;pong&#034;,&#8230;}<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">cmd<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">&#034;add&#034;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>        <span class=\"token comment\">\/\/ \u770b\u5230 {type:&#034;added&#034;,&#8230;}<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">cmd<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">&#034;snapshot&#034;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>   <span class=\"token comment\">\/\/ \u770b\u5230 {type:&#034;snapshot&#034;,&#8230;}<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">cmd<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">&#034;pickup&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token literal-property property\">arg<\/span><span class=\"token operator\">:<\/span> <span class=\"token number\">1<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>  <span class=\"token comment\">\/\/ \u770b id&#061;1 \u8ba2\u5355\u72b6\u6001<\/span><br \/>\nws<span class=\"token punctuation\">.<\/span><span class=\"token function\">send<\/span><span class=\"token punctuation\">(<\/span><span class=\"token constant\">JSON<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">stringify<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">cmd<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">&#034;haha&#034;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>       <span class=\"token comment\">\/\/ \u770b\u5230 {type:&#034;error&#034;, error:&#034;unknown cmd: haha&#034;}<\/span><\/p>\n<h3>8.7 \u81ea\u52a8\u751f\u6210\u7684 API \u6587\u6863&#xff08;\u5f69\u86cb&#xff09;<\/h3>\n<p>FastAPI \u81ea\u52a8\u751f\u6210\u4ea4\u4e92\u5f0f API \u6587\u6863&#xff0c;\u8bbf\u95ee&#xff1a;<\/p>\n<ul>\n<li>http:\/\/127.0.0.1:8000\/docs \u2014\u2014 Swagger UI<\/li>\n<li>http:\/\/127.0.0.1:8000\/redoc \u2014\u2014 ReDoc<\/li>\n<\/ul>\n<p>\u5728 \/docs \u91cc\u80fd\u770b\u5230 \/sse\/orders \u7b49 HTTP \u7aef\u70b9&#xff08;WebSocket \u7aef\u70b9\u4e0d\u663e\u793a\u5728 Swagger \u91cc&#xff0c;\u56e0\u4e3a OpenAPI \u89c4\u8303\u4e0d\u8986\u76d6 WS&#xff09;\u3002\u53ef\u4ee5\u76f4\u63a5\u5728\u9875\u9762\u4e0a\u300cTry it out\u300d\u6d4b\u8bd5 GET \u8def\u7531\u3002<\/p>\n<h3>8.8 \u5e38\u89c1\u95ee\u9898<\/h3>\n<h4>Q1&#xff1a;\u542f\u52a8\u62a5\u9519 ModuleNotFoundError: No module named &#039;fastapi&#039;<\/h4>\n<p>\u4f9d\u8d56\u6ca1\u88c5\u3002\u6267\u884c&#xff1a;<\/p>\n<p>uv <span class=\"token function\">sync<\/span>          <span class=\"token comment\"># \u7528 uv<\/span><br \/>\n<span class=\"token comment\"># \u6216<\/span><br \/>\npip <span class=\"token function\">install<\/span> fastapi <span class=\"token string\">&#034;uvicorn[standard]&#034;<\/span> websockets<\/p>\n<h4>Q2&#xff1a;Address already in use \/ \u7aef\u53e3 8000 \u88ab\u5360\u7528<\/h4>\n<p>\u4e0a\u6b21\u7684\u670d\u52a1\u6ca1\u5173\u5e72\u51c0\u3002\u6362\u7aef\u53e3&#xff1a;<\/p>\n<p>uv run python <span class=\"token parameter variable\">-m<\/span> uvicorn src.app:app <span class=\"token parameter variable\">&#8211;port<\/span> <span class=\"token number\">8001<\/span> <span class=\"token parameter variable\">&#8211;reload<\/span><\/p>\n<p>\u6216\u6740\u6389\u5360\u7528\u8fdb\u7a0b&#xff08;Windows&#xff09;&#xff1a;<\/p>\n<p><span class=\"token comment\"># \u627e\u5230\u5360\u7528 8000 \u7684 PID<\/span><br \/>\n<span class=\"token function\">netstat<\/span> <span class=\"token parameter variable\">-ano<\/span> <span class=\"token operator\">|<\/span> findstr :8000<br \/>\ntaskkill \/F \/PID <span class=\"token operator\">&lt;<\/span>PID<span class=\"token operator\">&gt;<\/span><\/p>\n<h4>Q3&#xff1a;\u6d4f\u89c8\u5668\u6253\u5f00\u662f\u7a7a\u767d \/ \u4e00\u76f4\u8f6c\u5708<\/h4>\n<ul>\n<li>\u786e\u8ba4 static\/index.html \u5b58\u5728\u4e14\u5185\u5bb9\u5b8c\u6574&#xff08;\u7b2c 7 \u7ae0&#xff09;&#xff1b;<\/li>\n<li>F12 \u770b Network&#xff0c;\/sse\/orders \u5e94\u662f pending \u72b6\u6001&#xff08;\u957f\u8fde\u63a5\u6b63\u5e38&#xff09;&#xff1b;\u5982\u679c\u7acb\u5373\u5931\u8d25&#xff0c;\u68c0\u67e5\u540e\u7aef\u65e5\u5fd7&#xff1b;<\/li>\n<li>\u770b\u63a7\u5236\u53f0\u6709\u65e0 JS \u62a5\u9519\u3002<\/li>\n<\/ul>\n<h4>Q4&#xff1a;SSE \u72b6\u6001\u706f\u4e00\u76f4\u7ea2 \/ \u300c\u65ad\u5f00, 3s \u540e\u91cd\u8fde\u300d<\/h4>\n<ul>\n<li>\u786e\u8ba4\u540e\u7aef\u5728\u8dd1&#xff1b;<\/li>\n<li>\u786e\u8ba4\u8bbf\u95ee\u7684\u662f http:\/\/127.0.0.1:8000\/&#xff08;\u4e0d\u662f localhost&#xff0c;\u6709\u65f6 cookie\/\u8de8\u57df\u95ee\u9898&#xff09;&#xff1b;<\/li>\n<li>\u7528 curl \u6d4b \/sse\/orders \u770b\u662f\u5426\u901a\u3002<\/li>\n<\/ul>\n<h4>Q5&#xff1a;\u8ba2\u5355\u4e0d\u5237\u65b0<\/h4>\n<ul>\n<li>\u770b\u540e\u7aef\u7ec8\u7aef\u662f\u5426\u6709\u62a5\u9519&#xff1b;<\/li>\n<li>models.py \u7684 advance() \u662f\u5426\u88ab broadcaster.py \u6b63\u786e\u8c03\u7528&#xff1b;<\/li>\n<li>app.py \u7684 lifespan \u662f\u5426\u7ed1\u5b9a\u4e86 broadcaster&#xff08;\u6f0f\u4e86 lifespan&#061;lifespan \u5c31\u4e0d\u4f1a\u8d77\u540e\u53f0\u4efb\u52a1&#xff09;\u3002<\/li>\n<\/ul>\n<h4>Q6&#xff1a;pickup \u4e00\u76f4\u62a5 not ready<\/h4>\n<p>\u8ba2\u5355\u5fc5\u987b**\u5148\u5230\u300c\u5df2\u5b8c\u6210\u300d**\u624d\u80fd\u53d6\u9910\u3002\u7b49\u8fdb\u5ea6\u6761\u6da8\u5230 100% \u72b6\u6001\u53d8\u6210\u300c\u5df2\u5b8c\u6210\u300d\u518d pickup\u3002\u6216\u5148 add \u4e00\u676f&#xff0c;\u591a\u7b49\u51e0\u4e2a tick\u3002<\/p>\n<h4>Q7&#xff1a;\u6539\u4e86\u4ee3\u7801\u4f46\u6ca1\u81ea\u52a8\u91cd\u542f<\/h4>\n<p>\u786e\u8ba4\u542f\u52a8\u547d\u4ee4\u5e26\u4e86 &#8211;reload\u3002\u6ce8\u610f &#8211;reload \u76d1\u89c6\u7684\u662f\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55&#xff0c;\u8981\u5728\u9879\u76ee\u6839\u76ee\u5f55\u542f\u52a8\u3002<\/p>\n<h4>Q8&#xff1a;Windows \u4e0b\u4e2d\u6587\u8def\u5f84\u62a5\u9519<\/h4>\n<p>\u9879\u76ee\u8def\u5f84\u542b\u4e2d\u6587&#xff08;\u5317\u4eac\u4e2d\u8f6f\/2026\/\u5317\u4eac\u90ae\u7535&#xff09;\u3002uvicorn \u4e00\u822c\u6ca1\u95ee\u9898&#xff0c;\u4f46\u5982\u679c\u6709\u7f16\u7801\u9519\u8bef&#xff0c;\u5c1d\u8bd5\u628a\u9879\u76ee\u79fb\u5230\u7eaf\u82f1\u6587\u8def\u5f84\u6d4b\u8bd5\u3002<\/p>\n<hr \/>\n<h3>8.9 \u505c\u6b62\u670d\u52a1<\/h3>\n<p>\u5728\u8fd0\u884c uvicorn \u7684\u7ec8\u7aef\u6309 Ctrl&#043;C\u3002<\/p>\n<p>\u505c\u6b62\u65f6\u4f1a\u770b\u5230&#xff1a;<\/p>\n<p>INFO:     Shutting down<br \/>\nINFO:     Waiting for application shutdown.<br \/>\nINFO:     Application shutdown complete.<\/p>\n<p>Application shutdown complete. \u8868\u793a lifespan \u7684 finally \u8dd1\u5b8c\u4e86&#xff0c;\u5e7f\u64ad\u5668\u5df2\u88ab cancel&#xff0c;\u5e72\u51c0\u9000\u51fa\u3002<\/p>\n<hr \/>\n<p>\u4e0b\u4e00\u7ae0 \u2192 09-SSE-vs-WebSocket.md&#xff1a;\u628a\u4e24\u79cd\u6280\u672f\u653e\u4e00\u8d77\u7cfb\u7edf\u5bf9\u6bd4 &#043; \u6269\u5c55\u7ec3\u4e60\u3002<\/p>\n<hr \/>\n<h2>\u7b2c 9 \u7ae0 \u00b7 SSE vs WebSocket \u5bf9\u6bd4\u4e0e\u6269\u5c55\u7ec3\u4e60<\/h2>\n<h3>\u672c\u7ae0\u76ee\u6807<\/h3>\n<p>\u628a\u524d\u9762\u5b66\u5230\u7684\u4e24\u79cd\u5b9e\u65f6\u901a\u4fe1\u6280\u672f\u653e\u5728\u4e00\u8d77\u7cfb\u7edf\u5bf9\u6bd4&#xff0c;\u5f62\u6210\u6e05\u6670\u7684\u77e5\u8bc6\u7f51\u7edc&#xff1b;\u518d\u7ed9\u51e0\u4e2a\u6269\u5c55\u7ec3\u4e60&#xff0c;\u5de9\u56fa\u7406\u89e3\u3002<\/p>\n<hr \/>\n<h3>9.1 \u5168\u9762\u5bf9\u6bd4\u8868<\/h3>\n<table>\n<tr>\u7ef4\u5ea6SSE (Server-Sent Events)WebSocket<\/tr>\n<tbody>\n<tr>\n<td>\u65b9\u5411<\/td>\n<td>\u5355\u5411&#xff08;\u670d\u52a1\u5668\u2192\u5ba2\u6237\u7aef&#xff09;<\/td>\n<td>\u5168\u53cc\u5de5&#xff08;\u53cc\u5411&#xff09;<\/td>\n<\/tr>\n<tr>\n<td>\u5e95\u5c42\u534f\u8bae<\/td>\n<td>HTTP&#xff08;\u666e\u901a GET \u54cd\u5e94\u6d41&#xff09;<\/td>\n<td>HTTP \u63e1\u624b\u540e\u5347\u7ea7\u4e3a ws:\/\/<\/td>\n<\/tr>\n<tr>\n<td>\u6d4f\u89c8\u5668 API<\/td>\n<td>new EventSource(url)<\/td>\n<td>new WebSocket(url)<\/td>\n<\/tr>\n<tr>\n<td>\u6570\u636e\u683c\u5f0f<\/td>\n<td>\u6587\u672c&#xff08;text\/event-stream \u5e27&#xff09;<\/td>\n<td>\u6587\u672c &#043; \u4e8c\u8fdb\u5236<\/td>\n<\/tr>\n<tr>\n<td>\u6d88\u606f\u8fb9\u754c<\/td>\n<td>\u7528\u7a7a\u884c\u5206\u9694\u6bcf\u5e27<\/td>\n<td>\u534f\u8bae\u81ea\u5e26\u5e27\u8fb9\u754c<\/td>\n<\/tr>\n<tr>\n<td>\u4e8b\u4ef6\u547d\u540d<\/td>\n<td>\u652f\u6301&#xff08;event: xxx&#xff09;<\/td>\n<td>\u81ea\u5df1\u7ea6\u5b9a&#xff08;\u901a\u5e38\u7528 type \u5b57\u6bb5&#xff09;<\/td>\n<\/tr>\n<tr>\n<td>\u81ea\u52a8\u91cd\u8fde<\/td>\n<td>\u2705 \u6d4f\u89c8\u5668\u5185\u7f6e<\/td>\n<td>\u274c \u9700\u624b\u52a8\u5b9e\u73b0<\/td>\n<\/tr>\n<tr>\n<td>\u91cd\u8fde\u95f4\u9694<\/td>\n<td>\u6d4f\u89c8\u5668\u63a7\u5236&#xff08;\u53ef\u914d retry: \u5b57\u6bb5&#xff09;<\/td>\n<td>\u81ea\u5df1\u5199 setTimeout<\/td>\n<\/tr>\n<tr>\n<td>\u8fde\u63a5\u6570\u9650\u5236<\/td>\n<td>\u6d4f\u89c8\u5668\u5bf9\u540c\u6e90\u6709\u9650\u5236&#xff08;\u901a\u5e38 6 \u4e2a&#xff09;<\/td>\n<td>\u65e0\u7279\u6b8a\u9650\u5236<\/td>\n<\/tr>\n<tr>\n<td>\u7a7f\u8d8a\u9632\u706b\u5899\/\u4ee3\u7406<\/td>\n<td>\u8f83\u597d&#xff08;\u5c31\u662f HTTP&#xff09;<\/td>\n<td>\u5076\u5c14\u88ab\u62e6&#xff08;\u9700 Upgrade \u5934&#xff09;<\/td>\n<\/tr>\n<tr>\n<td>HTTP \u4e2d\u95f4\u4ef6\u517c\u5bb9<\/td>\n<td>\u597d&#xff08;\u666e\u901a HTTP \u54cd\u5e94&#xff09;<\/td>\n<td>\u9700\u652f\u6301 Upgrade<\/td>\n<\/tr>\n<tr>\n<td>\u670d\u52a1\u7aef\u5b9e\u73b0<\/td>\n<td>StreamingResponse &#043; \u5f02\u6b65\u751f\u6210\u5668<\/td>\n<td>&#064;router.websocket &#043; accept\/receive\/send<\/td>\n<\/tr>\n<tr>\n<td>\u6bcf\u8fde\u63a5\u7f13\u51b2<\/td>\n<td>\u901a\u5e38\u914d asyncio.Queue<\/td>\n<td>\u53ef\u76f4\u63a5 send<\/td>\n<\/tr>\n<tr>\n<td>\u5178\u578b\u573a\u666f<\/td>\n<td>\u884c\u60c5\u3001\u901a\u77e5\u3001\u65e5\u5fd7\u6d41\u3001\u770b\u677f<\/td>\n<td>\u804a\u5929\u3001\u534f\u4f5c\u3001\u547d\u4ee4\u4ea4\u4e92\u3001\u6e38\u620f<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>9.2 \u5728\u672c\u9879\u76ee\u91cc\u7684\u5177\u4f53\u5dee\u5f02<\/h3>\n<table>\n<tr>\u7ef4\u5ea6sse.pyws.py<\/tr>\n<tbody>\n<tr>\n<td>\u88c5\u9970\u5668<\/td>\n<td>&#064;router.get(&#034;\/sse\/orders&#034;)<\/td>\n<td>&#064;router.websocket(&#034;\/ws\/orders&#034;)<\/td>\n<\/tr>\n<tr>\n<td>\u63e1\u624b<\/td>\n<td>\u65e0\u9700 accept<\/td>\n<td>await ws.accept()<\/td>\n<\/tr>\n<tr>\n<td>\u63a5\u6536\u5ba2\u6237\u7aef\u6d88\u606f<\/td>\n<td>\u274c \u4e0d\u80fd<\/td>\n<td>await ws.receive_text()<\/td>\n<\/tr>\n<tr>\n<td>\u53d1\u9001\u65b9\u5f0f<\/td>\n<td>yield &#034;event: &#8230;\\\\ndata: &#8230;\\\\n\\\\n&#034;<\/td>\n<td>await ws.send_text(json_str)<\/td>\n<\/tr>\n<tr>\n<td>\u5ba2\u6237\u7aef\u96c6\u5408\u5b58\u4ec0\u4e48<\/td>\n<td>asyncio.Queue&#xff08;\u7f13\u51b2&#xff09;<\/td>\n<td>WebSocket \u5bf9\u8c61&#xff08;\u76f4\u53d1&#xff09;<\/td>\n<\/tr>\n<tr>\n<td>\u5e7f\u64ad\u5668\u600e\u4e48\u5206\u53d1<\/td>\n<td>await queue.put({&#8230;})<\/td>\n<td>await ws.send_text(payload)<\/td>\n<\/tr>\n<tr>\n<td>\u65ad\u5f00\u5f02\u5e38<\/td>\n<td>GeneratorExit&#xff08;yield \u5904\u629b&#xff09;<\/td>\n<td>WebSocketDisconnect&#xff08;receive \u5904\u629b&#xff09;<\/td>\n<\/tr>\n<tr>\n<td>\u65ad\u5f00\u6e05\u7406<\/td>\n<td>finally: sse_clients.discard(queue)<\/td>\n<td>finally: ws_clients.discard(ws)<\/td>\n<\/tr>\n<tr>\n<td>\u5931\u8d25\u5904\u7406<\/td>\n<td>Queue \u4e0d\u4f1a\u5931\u8d25&#xff08;\u7f13\u51b2&#xff09;<\/td>\n<td>try\/except \u6355\u83b7 send \u5931\u8d25\u540e discard<\/td>\n<\/tr>\n<tr>\n<td>\u524d\u7aef\u8fde\u63a5<\/td>\n<td>new EventSource(&#039;\/sse\/orders&#039;)<\/td>\n<td>new WebSocket(&#039;ws:\/\/&#8230;&#039;)<\/td>\n<\/tr>\n<tr>\n<td>\u524d\u7aef\u91cd\u8fde<\/td>\n<td>onerror \u2192 close &#043; setTimeout<\/td>\n<td>onclose \u2192 setTimeout<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>9.3 \u8bbe\u8ba1\u54f2\u5b66\u5bf9\u6bd4<\/h3>\n<h4>SSE \u7684\u54f2\u5b66&#xff1a;\u300c\u591f\u7528\u5c31\u597d\u300d<\/h4>\n<ul>\n<li>\u5982\u679c\u4f60\u7684\u9700\u6c42\u662f\u300c\u670d\u52a1\u5668\u63a8\u3001\u5ba2\u6237\u7aef\u53ea\u770b\u300d&#xff0c;SSE \u662f\u6700\u7b80\u5355\u7684\u65b9\u6848&#xff1b;<\/li>\n<li>\u57fa\u4e8e HTTP&#xff0c;\u6240\u6709 HTTP \u57fa\u7840\u8bbe\u65bd&#xff08;\u7f13\u5b58\u3001\u4ee3\u7406\u3001\u538b\u7f29\u3001CORS&#xff09;\u90fd\u80fd\u76f4\u63a5\u7528&#xff1b;<\/li>\n<li>\u6d4f\u89c8\u5668\u81ea\u52a8\u91cd\u8fde\u3001\u81ea\u52a8\u6062\u590d&#xff0c;\u7701\u5fc3&#xff1b;<\/li>\n<li>\u672c\u9879\u76ee\u300c\u5b9e\u65f6\u8ba2\u5355\u770b\u677f\u300d\u5c31\u662f\u5178\u578b\u573a\u666f\u2014\u2014\u670d\u52a1\u5668\u63a8\u8ba2\u5355\u3001\u6d4f\u89c8\u5668\u53ea\u6e32\u67d3&#xff0c;SSE \u5b8c\u5168\u591f\u7528\u3002<\/li>\n<\/ul>\n<h4>WebSocket \u7684\u54f2\u5b66&#xff1a;\u300c\u9700\u8981\u4ea4\u4e92\u624d\u4e0a\u300d<\/h4>\n<ul>\n<li>\u5982\u679c\u5ba2\u6237\u7aef\u8981\u4e3b\u52a8\u53d1\u6d88\u606f&#xff08;\u547d\u4ee4\u3001\u804a\u5929\u3001\u63a7\u5236&#xff09;&#xff0c;\u5fc5\u987b\u53cc\u5411&#xff0c;\u7528 WS&#xff1b;<\/li>\n<li>\u4f46\u4ee3\u4ef7\u662f&#xff1a;\u63e1\u624b\u66f4\u590d\u6742\u3001\u91cd\u8fde\u8981\u81ea\u5df1\u5199\u3001\u4ee3\u7406\u517c\u5bb9\u6027\u8981\u6d4b\u3001\u6d88\u606f\u683c\u5f0f\u8981\u81ea\u5df1\u7ea6\u5b9a&#xff1b;<\/li>\n<li>\u672c\u9879\u76ee\u300c\u5e97\u5458\u64cd\u4f5c\u53f0\u300d\u9700\u8981\u53d1 ping\/add\/pickup\/snapshot \u547d\u4ee4&#xff0c;\u5fc5\u987b WS\u3002<\/li>\n<\/ul>\n<p>\u7ecf\u9a8c\u6cd5\u5219&#xff1a;\u80fd\u7528 SSE \u5c31\u522b\u4e0a WS\u3002SSE \u7684\u7b80\u5355\u6027\u5728\u957f\u671f\u7ef4\u62a4\u91cc\u4ef7\u503c\u5de8\u5927\u3002\u53ea\u6709\u786e\u8ba4\u9700\u8981\u53cc\u5411&#xff0c;\u624d\u7528 WS\u3002<\/p>\n<h3>9.4 \u672c\u9879\u76ee\u7684\u67b6\u6784\u5de7\u601d<\/h3>\n<h4>9.4.1 \u5171\u4eab\u5fc3\u8df3\u6e90<\/h4>\n<p>\u4e24\u4e2a\u4f20\u8f93\u6a21\u5757\u5404\u81ea\u7ef4\u62a4\u8ba2\u9605\u8005\u96c6\u5408&#xff0c;\u4f46\u53ea\u6709\u4e00\u4e2a\u5e7f\u64ad\u5668\u8c03 advance()\u3002\u4fdd\u8bc1&#xff1a;<\/p>\n<ul>\n<li>\u72b6\u6001\u63a8\u8fdb\u53ea\u53d1\u751f\u4e00\u6b21&#xff08;\u4e0d\u4f1a\u6309\u8fde\u63a5\u6570\u500d\u589e&#xff09;&#xff1b;<\/li>\n<li>\u6240\u6709\u8fde\u63a5\u770b\u5230\u540c\u4e00\u65f6\u523b\u7684\u6570\u636e\u3002<\/li>\n<\/ul>\n<h4>9.4.2 \u6570\u636e\u5c42\u5b8c\u5168\u89e3\u8026<\/h4>\n<p>models.py \u4e0d\u77e5\u9053 SSE\/WS \u7684\u5b58\u5728\u3002\u597d\u5904&#xff1a;<\/p>\n<ul>\n<li>\u60f3\u6362\u4f20\u8f93\u5c42&#xff08;\u5982\u6362\u6210\u7eaf\u8f6e\u8be2\u3001\u6216\u6362\u6210 Socket.IO&#xff09;\u4e0d\u7528\u52a8\u6570\u636e\u5c42&#xff1b;<\/li>\n<li>\u5355\u5143\u6d4b\u8bd5\u6570\u636e\u5c42\u65f6\u4e0d\u9700\u8d77\u670d\u52a1\u5668&#xff1b;<\/li>\n<li>\u6570\u636e\u5c42\u53ef\u4ee5\u5355\u72ec\u590d\u7528&#xff08;\u5982\u505a\u547d\u4ee4\u884c\u7248\u770b\u677f&#xff09;\u3002<\/li>\n<\/ul>\n<h4>9.4.3 \u4e24\u79cd\u5206\u53d1\u7b56\u7565\u5bf9\u7167<\/h4>\n<ul>\n<li>SSE \u7528 Queue \u7f13\u51b2&#xff1a;\u751f\u4ea7\u8005&#xff08;\u5e7f\u64ad\u5668&#xff09;\u548c\u6d88\u8d39\u8005&#xff08;\u8fde\u63a5\u534f\u7a0b&#xff09;\u89e3\u8026&#xff0c;\u5e7f\u64ad\u5668\u4e0d\u4f1a\u88ab\u6162\u5ba2\u6237\u7aef\u5361\u4f4f\u3002\u4ee3\u4ef7\u662f\u65ad\u8fde\u6e05\u7406\u9760\u534f\u7a0b finally&#xff1b;<\/li>\n<li>WS \u76f4\u63a5 send&#xff1a;\u5b9e\u65f6\u6027\u597d\u3001\u5931\u8d25\u5373\u77e5\u3002\u4ee3\u4ef7\u662f\u5e7f\u64ad\u5668\u8981\u5904\u7406\u53d1\u9001\u5931\u8d25\u3002<\/li>\n<\/ul>\n<p>\u8fd9\u662f\u6559\u5b66\u9879\u76ee\u6545\u610f\u505a\u7684\u5bf9\u7167\u2014\u2014\u540c\u4e00\u79cd\u300c\u5e7f\u64ad\u300d\u9700\u6c42&#xff0c;\u4e24\u79cd\u5b9e\u73b0\u601d\u8def\u3002<\/p>\n<h4>9.4.4 \u524d\u7aef\u5206\u5de5<\/h4>\n<ul>\n<li>\u5de6\u4fa7 SSE \u770b\u300c\u81ea\u52a8\u63a8\u9001\u7684\u8ba2\u5355\u300d&#xff1b;<\/li>\n<li>\u53f3\u4fa7 WS \u770b\u300c\u547d\u4ee4\u4ea4\u4e92 &#043; \u901a\u4fe1\u65e5\u5fd7\u300d&#xff1b;<\/li>\n<li>\u4e24\u8fb9\u8ba2\u5355\u5361\u7247\u7528\u540c\u4e00\u4e2a renderOrders \u51fd\u6570&#xff0c;\u4ee3\u7801\u590d\u7528\u3002<\/li>\n<\/ul>\n<hr \/>\n<h3>9.5 \u6269\u5c55\u7ec3\u4e60<\/h3>\n<p>\u6309\u96be\u5ea6\u6392\u5e8f&#xff0c;\u505a\u5b8c\u80fd\u52a0\u6df1\u7406\u89e3\u3002<\/p>\n<h4>&#x1f7e2; \u7ec3\u4e60 1&#xff08;\u7b80\u5355&#xff09;&#xff1a;\u8c03\u6162\u5e7f\u64ad&#xff0c;\u89c2\u5bdf\u7ec6\u8282<\/h4>\n<p>\u628a broadcaster.py \u7684 interval \u6539\u6210 2.0&#xff0c;\u91cd\u542f\u3002\u89c2\u5bdf&#xff1a;<\/p>\n<ul>\n<li>\u8ba2\u5355\u63a8\u8fdb\u53d8\u6162&#xff0c;\u80fd\u6e05\u695a\u770b\u5230\u6bcf\u4e2a\u72b6\u6001\u505c\u7559&#xff1b;<\/li>\n<li>\u524d\u7aef\u65ad\u5f00\u91cd\u8fde\u7684 3 \u79d2\u548c 2 \u79d2\u5e7f\u64ad\u7684\u5173\u7cfb\u3002<\/li>\n<\/ul>\n<h4>&#x1f7e2; \u7ec3\u4e60 2&#xff08;\u7b80\u5355&#xff09;&#xff1a;\u52a0\u4e00\u4e2a clear \u547d\u4ee4<\/h4>\n<p>\u5728 ws.py \u52a0\u4e00\u4e2a clear \u547d\u4ee4&#xff0c;\u6e05\u7a7a\u6240\u6709\u8ba2\u5355&#xff1a;<\/p>\n<p><span class=\"token keyword\">elif<\/span> cmd <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;clear&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    orders<span class=\"token punctuation\">.<\/span>clear<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">await<\/span> send<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;type&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;cleared&#034;<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>\u524d\u7aef\u52a0\u4e2a\u6309\u94ae onclick&#061;&#039;sendCmd({cmd:&#034;clear&#034;})&#039;\u3002\u6ce8\u610f clear \u540e order_seq \u4e0d\u4f1a\u91cd\u7f6e&#xff0c;\u65b0\u8ba2\u5355\u53f7\u4f1a\u63a5\u7740\u6da8\u2014\u2014\u60f3\u60f3\u4e3a\u4ec0\u4e48&#xff08;count \u662f\u6a21\u5757\u7ea7\u5168\u5c40&#xff09;\u3002<\/p>\n<h4>&#x1f7e1; \u7ec3\u4e60 3&#xff08;\u4e2d\u7b49&#xff09;&#xff1a;\u7ed9 SSE \u4e5f\u52a0\u91cd\u8fde\u6b21\u6570\u663e\u793a<\/h4>\n<p>\u6539 connectSSE&#xff0c;\u7528\u4e00\u4e2a\u53d8\u91cf\u8bb0\u5f55\u91cd\u8fde\u6b21\u6570&#xff0c;\u5728\u72b6\u6001\u706f\u65c1\u663e\u793a\u300cSSE: \u5df2\u8fde\u63a5&#xff08;\u91cd\u8fde 2 \u6b21&#xff09;\u300d\u3002<\/p>\n<h4>&#x1f7e1; \u7ec3\u4e60 4&#xff08;\u4e2d\u7b49&#xff09;&#xff1a;\u8ba9 pickup \u4e5f\u80fd\u5728 SSE \u770b\u677f\u89e6\u53d1<\/h4>\n<p>\u73b0\u5728 pickup \u53ea\u6539 WS \u770b\u5230\u7684\u8ba2\u5355\u3002\u4f46\u56e0\u4e3a orders \u662f\u5171\u4eab\u7684&#xff0c;\u4e0b\u4e00\u6b21\u5e7f\u64ad&#xff08;0.8s&#xff09;SSE \u770b\u677f\u4e5f\u4f1a\u66f4\u65b0\u3002\u7ed9\u5de6\u4fa7\u6bcf\u5f20\u300c\u5df2\u5b8c\u6210\u300d\u5361\u7247\u52a0\u4e00\u4e2a\u300c\u53d6\u9910\u300d\u6309\u94ae&#xff0c;\u70b9\u51fb\u65f6\u901a\u8fc7 window._ws \u53d1 pickup \u547d\u4ee4&#xff0c;\u89c2\u5bdf\u5de6\u4fa7\u5728\u4e0b\u4e00\u6b21\u5e7f\u64ad\u540e\u4e5f\u66f4\u65b0\u3002\u8fd9\u80fd\u76f4\u89c2\u4f53\u4f1a\u300c\u5171\u4eab\u6570\u636e\u6e90\u300d\u3002<\/p>\n<h4>&#x1f7e1; \u7ec3\u4e60 5&#xff08;\u4e2d\u7b49&#xff09;&#xff1a;\u5e7f\u64ad\u5668\u63a8\u7ed9 WS \u7684\u6d88\u606f\u4e5f\u5e26 type<\/h4>\n<p>\u73b0\u5728\u5e7f\u64ad\u5668\u63a8\u7ed9 WS \u7684\u662f\u7eaf\u5feb\u7167 {&#034;time&#034;:&#8230;,&#034;orders&#034;:[&#8230;]}&#xff0c;\u6ca1\u6709 type\u3002\u524d\u7aef\u9760\u300c\u6ca1\u6709 type \u5c31\u5f53\u8ba2\u5355\u66f4\u65b0\u300d\u5224\u65ad\u3002\u6539\u6210&#xff1a;\u5e7f\u64ad\u5668\u63a8 {&#034;type&#034;:&#034;orders&#034;,&#034;time&#034;:&#8230;,&#034;orders&#034;:[&#8230;]}&#xff0c;\u524d\u7aef onmessage \u91cc\u52a0 if (msg.type &#061;&#061;&#061; &#034;orders&#034;) renderOrders(box, msg.orders)\u3002\u8fd9\u6837 WS \u7aef\u7684\u8ba2\u5355\u4e5f\u5b9e\u65f6\u5237\u65b0&#xff08;\u76ee\u524d WS \u7aef\u53ea\u9760 hello\/snapshot \u6e32\u67d3&#xff09;\u3002<\/p>\n<h4>&#x1f534; \u7ec3\u4e60 6&#xff08;\u8fdb\u9636&#xff09;&#xff1a;\u52a0\u5fc3\u8df3\u68c0\u6d4b<\/h4>\n<p>WS \u8fde\u63a5\u957f\u65f6\u95f4\u6ca1\u6d88\u606f\u4f1a\u88ab\u4e2d\u95f4\u4ee3\u7406\u65ad\u5f00\u3002\u52a0\u4e00\u4e2a\u5fc3\u8df3&#xff1a;\u524d\u7aef\u6bcf 30 \u79d2\u53d1 {&#034;cmd&#034;:&#034;ping&#034;}&#xff0c;\u670d\u52a1\u7aef\u56de pong\u3002\u5982\u679c 2 \u6b21 ping \u6ca1\u6536\u5230 pong&#xff0c;\u8ba4\u4e3a\u65ad\u5f00&#xff0c;\u4e3b\u52a8 ws.close() \u89e6\u53d1\u91cd\u8fde\u3002<\/p>\n<h4>&#x1f534; \u7ec3\u4e60 7&#xff08;\u8fdb\u9636&#xff09;&#xff1a;\u6301\u4e45\u5316<\/h4>\n<p>\u73b0\u5728\u8ba2\u5355\u5b58\u5728\u5185\u5b58 dict&#xff0c;\u91cd\u542f\u5c31\u6ca1\u4e86\u3002\u52a0\u4e00\u4e2a\u7b80\u5355\u6301\u4e45\u5316&#xff1a;\u6bcf 10 \u79d2\u628a orders \u5199\u5230 state.json&#xff0c;\u542f\u52a8\u65f6\u8bfb\u56de\u6765\u3002\u6ce8\u610f order_seq \u4e5f\u8981\u6301\u4e45\u5316&#xff08;\u6216\u542f\u52a8\u65f6\u626b\u4e00\u904d orders \u627e\u6700\u5927 id&#xff09;\u3002<\/p>\n<h4>&#x1f534; \u7ec3\u4e60 8&#xff08;\u8fdb\u9636&#xff09;&#xff1a;\u628a SSE \u770b\u677f\u6539\u6210\u53ea\u7528 WS<\/h4>\n<p>\u628a\u5de6\u4fa7\u4e5f\u6539\u6210\u7528 WebSocket&#xff08;\u590d\u7528\u53f3\u4fa7\u7684\u8fde\u63a5&#xff0c;\u6216\u65b0\u5f00\u4e00\u4e2a WS&#xff09;\u3002\u4f53\u4f1a&#xff1a;\u53ea\u7528 WS \u4e5f\u80fd\u505a\u770b\u677f&#xff0c;\u4f46\u4ee3\u7801\u6bd4 SSE \u590d\u6742&#xff08;\u8981\u81ea\u5df1\u5904\u7406\u6d88\u606f\u7c7b\u578b\u5206\u53d1&#xff09;\u3002\u7136\u540e\u6539\u56de SSE&#xff0c;\u4f53\u4f1a SSE \u7684\u7b80\u6d01\u3002<\/p>\n<hr \/>\n<h3>9.6 \u5b66\u5b8c\u4f60\u5e94\u8be5\u638c\u63e1\u7684\u6982\u5ff5<\/h3>\n<ul>\n<li class=\"task-list-item\"> SSE \u662f\u4ec0\u4e48\u3001\u4e3a\u4ec0\u4e48\u662f\u5355\u5411\u3001\u57fa\u4e8e HTTP<\/li>\n<li class=\"task-list-item\"> EventSource \u7684\u7528\u6cd5\u3001\u81ea\u52a8\u91cd\u8fde<\/li>\n<li class=\"task-list-item\"> SSE \u5e27\u683c\u5f0f&#xff08;event: \/ data: \/ \u7a7a\u884c&#xff09;<\/li>\n<li class=\"task-list-item\"> StreamingResponse &#043; \u5f02\u6b65\u751f\u6210\u5668\u5b9e\u73b0 SSE<\/li>\n<li class=\"task-list-item\"> WebSocket \u662f\u4ec0\u4e48\u3001\u4e3a\u4ec0\u4e48\u662f\u53cc\u5411\u3001\u63e1\u624b\u5347\u7ea7<\/li>\n<li class=\"task-list-item\"> WebSocket \u7684\u7528\u6cd5\u3001accept\/receive\/send\u3001\u624b\u52a8\u91cd\u8fde<\/li>\n<li class=\"task-list-item\"> FastAPI \u7684 &#064;router.websocket \u5199\u6cd5<\/li>\n<li class=\"task-list-item\"> WebSocketDisconnect \u5f02\u5e38\u5904\u7406<\/li>\n<li class=\"task-list-item\"> \u540e\u53f0\u4efb\u52a1\u7528 asyncio.create_task &#043; lifespan \u7ba1\u7406<\/li>\n<li class=\"task-list-item\"> \u7528 asyncio.Queue \u89e3\u8026\u751f\u4ea7\u8005\/\u6d88\u8d39\u8005<\/li>\n<li class=\"task-list-item\"> TypedDict \u505a\u6d88\u606f\u7c7b\u578b\u5951\u7ea6<\/li>\n<li class=\"task-list-item\"> \u6a21\u5757\u5316\u8def\u7531 APIRouter &#043; include_router<\/li>\n<li class=\"task-list-item\"> \u6570\u636e\u5c42\u4e0e\u4f20\u8f93\u5c42\u89e3\u8026\u7684\u8bbe\u8ba1<\/li>\n<li class=\"task-list-item\"> \u5171\u4eab\u5fc3\u8df3\u6e90\u907f\u514d\u91cd\u590d\u63a8\u8fdb<\/li>\n<\/ul>\n<h3>9.7 \u63a8\u8350\u7ee7\u7eed\u5b66\u4e60<\/h3>\n<ul>\n<li>Socket.IO&#xff1a;\u5728 WS \u4e4b\u4e0a\u52a0\u4e86\u623f\u95f4\u3001\u547d\u540d\u7a7a\u95f4\u3001\u81ea\u52a8\u91cd\u8fde\u3001\u964d\u7ea7\u7b49&#xff0c;\u9002\u5408\u590d\u6742\u5b9e\u65f6\u573a\u666f&#xff1b;<\/li>\n<li>HTTP\/2 Server Push \/ HTTP Streaming&#xff1a;\u548c SSE \u76f8\u5173\u7684 HTTP \u7279\u6027&#xff1b;<\/li>\n<li>FastAPI \u5b98\u65b9\u6587\u6863\u7684 Streaming Responses \u548c WebSockets \u7ae0\u8282&#xff1b;<\/li>\n<li>uvicorn \/ Starlette \u7684 lifespan\u3001\u4e2d\u95f4\u4ef6\u673a\u5236\u3002<\/li>\n<\/ul>\n<h3>9.8 \u7ed3\u8bed<\/h3>\n<p>\u8fd9\u4e2a\u9879\u76ee\u7528\u4e00\u676f\u5976\u8336\u7684\u8ba2\u5355\u6d41\u8f6c&#xff0c;\u628a SSE \u548c WebSocket \u4e24\u79cd\u5b9e\u65f6\u6280\u672f\u653e\u5728\u540c\u4e00\u4e2a\u6570\u636e\u6e90\u4e0a\u5bf9\u6bd4\u3002\u5e0c\u671b\u4f60\u770b\u5b8c\u80fd\u8bb0\u4f4f\u90a3\u53e5\u8bdd&#xff1a;<\/p>\n<p>\u80fd\u7528 SSE \u5c31\u522b\u4e0a WS&#xff1b;\u786e\u8ba4\u9700\u8981\u53cc\u5411&#xff0c;\u624d\u7528 WS\u3002<\/p>\n<p>\u606d\u559c\u4f60\u4ece\u5934\u5199\u5b8c\u4e86\u6574\u4e2a\u9879\u76ee &#x1f389;\u3002<\/p>\n<hr \/>\n","protected":false},"excerpt":{"rendered":"<p>fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f \u7528 FastAPI \u4ece\u96f6\u642d\u4e00\u4e2a\u300c\u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f\u300d&#xff0c;\u628a SSE&#xff08;\u5355\u5411\u63a8\u9001&#xff09; \u548c WebSocket&#xff08;\u53cc\u5411\u901a\u9053&#xff09; \u4e24\u4e2a\u5b9e\u65f6\u901a\u4fe1\u6280\u672f\u653e\u5728\u540c\u4e00\u4e2a\u9879\u76ee\u91cc\u5bf9\u6bd4\u5b66\u4e60\u3002 \u8fd9\u4efd\u6559\u53ea\u8981\u8ddf\u7740\u7ae0\u8282\u987a\u5e8f\u8bfb\u3001\u6309\u6b65\u9aa4\u6572\u4ee3\u7801&#xff0c;\u5c31\u80fd\u72ec\u7acb\u5199\u5b8c\u6240\u6709\u6587\u4ef6\u5e76\u8ba9\u9879\u76ee\u8dd1\u8d77\u6765\u3002\u6bcf\u4e00\u7ae0\u90fd\u5305\u542b&#xff1a;<br \/>\n\u672c\u7ae0\u76ee\u6807 \u2014\u2014 \u8fd9\u7ae0\u8981\u89e3\u51b3\u4ec0\u4e48\u95ee\u9898&#xff1b;\u539f\u59cb\u5b8c\u6574\u4ee3\u7801 \u2014<\/p>\n","protected":false},"author":2,"featured_media":90028,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[72,81,234,947,191],"topic":[],"class_list":["post-90032","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-server","tag-fastapi","tag-python","tag-sse","tag-websocket","tag-191"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v20.3 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.wsisp.com\/helps\/90032.html\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\" \/>\n<meta property=\"og:description\" content=\"fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f \u7528 FastAPI \u4ece\u96f6\u642d\u4e00\u4e2a\u300c\u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f\u300d&#xff0c;\u628a SSE&#xff08;\u5355\u5411\u63a8\u9001&#xff09; \u548c WebSocket&#xff08;\u53cc\u5411\u901a\u9053&#xff09; \u4e24\u4e2a\u5b9e\u65f6\u901a\u4fe1\u6280\u672f\u653e\u5728\u540c\u4e00\u4e2a\u9879\u76ee\u91cc\u5bf9\u6bd4\u5b66\u4e60\u3002 \u8fd9\u4efd\u6559\u53ea\u8981\u8ddf\u7740\u7ae0\u8282\u987a\u5e8f\u8bfb\u3001\u6309\u6b65\u9aa4\u6572\u4ee3\u7801&#xff0c;\u5c31\u80fd\u72ec\u7acb\u5199\u5b8c\u6240\u6709\u6587\u4ef6\u5e76\u8ba9\u9879\u76ee\u8dd1\u8d77\u6765\u3002\u6bcf\u4e00\u7ae0\u90fd\u5305\u542b&#xff1a; \u672c\u7ae0\u76ee\u6807 \u2014\u2014 \u8fd9\u7ae0\u8981\u89e3\u51b3\u4ec0\u4e48\u95ee\u9898&#xff1b;\u539f\u59cb\u5b8c\u6574\u4ee3\u7801 \u2014\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.wsisp.com\/helps\/90032.html\" \/>\n<meta property=\"og:site_name\" content=\"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-04T08:17:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/08\/20260804081737-6a71a021780c1.png\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"48 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/90032.html\",\"url\":\"https:\/\/www.wsisp.com\/helps\/90032.html\",\"name\":\"fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\",\"isPartOf\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/#website\"},\"datePublished\":\"2026-08-04T08:17:43+00:00\",\"dateModified\":\"2026-08-04T08:17:43+00:00\",\"author\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/90032.html#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.wsisp.com\/helps\/90032.html\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/90032.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\/\/www.wsisp.com\/helps\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#website\",\"url\":\"https:\/\/www.wsisp.com\/helps\/\",\"name\":\"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\",\"description\":\"\u9999\u6e2f\u670d\u52a1\u5668_\u9999\u6e2f\u4e91\u670d\u52a1\u5668\u8d44\u8baf_\u670d\u52a1\u5668\u5e2e\u52a9\u6587\u6863_\u670d\u52a1\u5668\u6559\u7a0b\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.wsisp.com\/helps\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"zh-Hans\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery\",\"contentUrl\":\"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery\",\"caption\":\"admin\"},\"sameAs\":[\"http:\/\/wp.wsisp.com\"],\"url\":\"https:\/\/www.wsisp.com\/helps\/author\/admin\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.wsisp.com\/helps\/90032.html","og_locale":"zh_CN","og_type":"article","og_title":"fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","og_description":"fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f \u7528 FastAPI \u4ece\u96f6\u642d\u4e00\u4e2a\u300c\u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f\u300d&#xff0c;\u628a SSE&#xff08;\u5355\u5411\u63a8\u9001&#xff09; \u548c WebSocket&#xff08;\u53cc\u5411\u901a\u9053&#xff09; \u4e24\u4e2a\u5b9e\u65f6\u901a\u4fe1\u6280\u672f\u653e\u5728\u540c\u4e00\u4e2a\u9879\u76ee\u91cc\u5bf9\u6bd4\u5b66\u4e60\u3002 \u8fd9\u4efd\u6559\u53ea\u8981\u8ddf\u7740\u7ae0\u8282\u987a\u5e8f\u8bfb\u3001\u6309\u6b65\u9aa4\u6572\u4ee3\u7801&#xff0c;\u5c31\u80fd\u72ec\u7acb\u5199\u5b8c\u6240\u6709\u6587\u4ef6\u5e76\u8ba9\u9879\u76ee\u8dd1\u8d77\u6765\u3002\u6bcf\u4e00\u7ae0\u90fd\u5305\u542b&#xff1a; \u672c\u7ae0\u76ee\u6807 \u2014\u2014 \u8fd9\u7ae0\u8981\u89e3\u51b3\u4ec0\u4e48\u95ee\u9898&#xff1b;\u539f\u59cb\u5b8c\u6574\u4ee3\u7801 \u2014","og_url":"https:\/\/www.wsisp.com\/helps\/90032.html","og_site_name":"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","article_published_time":"2026-08-04T08:17:43+00:00","og_image":[{"url":"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/08\/20260804081737-6a71a021780c1.png"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"admin","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"48 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.wsisp.com\/helps\/90032.html","url":"https:\/\/www.wsisp.com\/helps\/90032.html","name":"fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","isPartOf":{"@id":"https:\/\/www.wsisp.com\/helps\/#website"},"datePublished":"2026-08-04T08:17:43+00:00","dateModified":"2026-08-04T08:17:43+00:00","author":{"@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41"},"breadcrumb":{"@id":"https:\/\/www.wsisp.com\/helps\/90032.html#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.wsisp.com\/helps\/90032.html"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.wsisp.com\/helps\/90032.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/www.wsisp.com\/helps"},{"@type":"ListItem","position":2,"name":"fastapi sse websocket \u5976\u8336\u5e97\u5b9e\u65f6\u8ba2\u5355\u770b\u677f"}]},{"@type":"WebSite","@id":"https:\/\/www.wsisp.com\/helps\/#website","url":"https:\/\/www.wsisp.com\/helps\/","name":"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","description":"\u9999\u6e2f\u670d\u52a1\u5668_\u9999\u6e2f\u4e91\u670d\u52a1\u5668\u8d44\u8baf_\u670d\u52a1\u5668\u5e2e\u52a9\u6587\u6863_\u670d\u52a1\u5668\u6559\u7a0b","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.wsisp.com\/helps\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"zh-Hans"},{"@type":"Person","@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41","name":"admin","image":{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/image\/","url":"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery","contentUrl":"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery","caption":"admin"},"sameAs":["http:\/\/wp.wsisp.com"],"url":"https:\/\/www.wsisp.com\/helps\/author\/admin"}]}},"_links":{"self":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts\/90032","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/comments?post=90032"}],"version-history":[{"count":0,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts\/90032\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/media\/90028"}],"wp:attachment":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/media?parent=90032"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/categories?post=90032"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/tags?post=90032"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/topic?post=90032"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}