2026-02-06 03:34:50 +08:00
|
|
|
<template>
|
|
|
|
|
<div class="demo-container">
|
|
|
|
|
<h4>事件循环 (Event Loop) 演示</h4>
|
|
|
|
|
|
|
|
|
|
<div class="controls">
|
2026-02-18 17:38:10 +08:00
|
|
|
<el-button
|
|
|
|
|
type="primary"
|
|
|
|
|
size="small"
|
|
|
|
|
:disabled="isRunning"
|
|
|
|
|
@click="startSimulation"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
{{ isRunning ? '运行中...' : '开始模拟' }}
|
|
|
|
|
</el-button>
|
2026-02-18 17:38:10 +08:00
|
|
|
<el-button
|
|
|
|
|
size="small"
|
|
|
|
|
:disabled="tasks.length >= 10"
|
|
|
|
|
@click="addTask"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
添加任务
|
|
|
|
|
</el-button>
|
2026-02-18 17:38:10 +08:00
|
|
|
<el-button
|
|
|
|
|
size="small"
|
|
|
|
|
:disabled="microtasks.length >= 5"
|
|
|
|
|
@click="addMicrotask"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
添加微任务
|
|
|
|
|
</el-button>
|
2026-02-18 17:38:10 +08:00
|
|
|
<el-button
|
|
|
|
|
size="small"
|
|
|
|
|
@click="reset"
|
|
|
|
|
>
|
|
|
|
|
重置
|
|
|
|
|
</el-button>
|
2026-02-06 03:34:50 +08:00
|
|
|
|
2026-02-18 17:38:10 +08:00
|
|
|
<el-select
|
|
|
|
|
v-model="simulationSpeed"
|
|
|
|
|
size="small"
|
|
|
|
|
style="width: 120px;"
|
|
|
|
|
>
|
|
|
|
|
<el-option
|
|
|
|
|
:value="1"
|
|
|
|
|
label="慢速"
|
|
|
|
|
/>
|
|
|
|
|
<el-option
|
|
|
|
|
:value="2"
|
|
|
|
|
label="正常"
|
|
|
|
|
/>
|
|
|
|
|
<el-option
|
|
|
|
|
:value="3"
|
|
|
|
|
label="快速"
|
|
|
|
|
/>
|
|
|
|
|
<el-option
|
|
|
|
|
:value="4"
|
|
|
|
|
label="极快"
|
|
|
|
|
/>
|
|
|
|
|
<el-option
|
|
|
|
|
:value="5"
|
|
|
|
|
label="即时"
|
|
|
|
|
/>
|
2026-02-06 03:34:50 +08:00
|
|
|
</el-select>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="event-loop-container">
|
|
|
|
|
<!-- 调用栈 -->
|
|
|
|
|
<div class="section">
|
2026-02-18 17:38:10 +08:00
|
|
|
<div class="section-title">
|
|
|
|
|
调用栈 (Call Stack)
|
|
|
|
|
</div>
|
2026-02-06 03:34:50 +08:00
|
|
|
<div class="stack-container">
|
2026-02-18 17:38:10 +08:00
|
|
|
<div
|
|
|
|
|
v-for="(frame, idx) in callStack"
|
|
|
|
|
:key="idx"
|
|
|
|
|
class="stack-frame"
|
|
|
|
|
:class="{ active: idx === 0 }"
|
|
|
|
|
:style="{ animationDelay: idx * 0.1 + 's' }"
|
|
|
|
|
>
|
|
|
|
|
<div class="frame-name">
|
|
|
|
|
{{ frame.name }}
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
v-if="frame.line"
|
|
|
|
|
class="frame-line"
|
|
|
|
|
>
|
|
|
|
|
第 {{ frame.line }} 行
|
|
|
|
|
</div>
|
2026-02-06 03:34:50 +08:00
|
|
|
</div>
|
2026-02-18 17:38:10 +08:00
|
|
|
<div
|
|
|
|
|
v-if="callStack.length === 0"
|
|
|
|
|
class="empty-stack"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
栈为空
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 事件循环 -->
|
|
|
|
|
<div class="section event-loop">
|
2026-02-18 17:38:10 +08:00
|
|
|
<div class="section-title">
|
|
|
|
|
事件循环 (Event Loop)
|
|
|
|
|
</div>
|
2026-02-06 03:34:50 +08:00
|
|
|
<div class="loop-container">
|
2026-02-18 17:38:10 +08:00
|
|
|
<div
|
|
|
|
|
class="loop-arrow"
|
|
|
|
|
:class="{ rotating: isRunning }"
|
|
|
|
|
>
|
|
|
|
|
<svg
|
|
|
|
|
viewBox="0 0 100 100"
|
|
|
|
|
class="loop-svg"
|
|
|
|
|
>
|
|
|
|
|
<circle
|
|
|
|
|
cx="50"
|
|
|
|
|
cy="50"
|
|
|
|
|
r="40"
|
|
|
|
|
fill="none"
|
|
|
|
|
stroke="#409eff"
|
|
|
|
|
stroke-width="4"
|
|
|
|
|
stroke-dasharray="200"
|
|
|
|
|
stroke-linecap="round"
|
|
|
|
|
class="loop-circle"
|
|
|
|
|
/>
|
|
|
|
|
<polygon
|
|
|
|
|
points="85,50 75,45 75,55"
|
|
|
|
|
fill="#409eff"
|
|
|
|
|
class="loop-arrowhead"
|
|
|
|
|
/>
|
2026-02-06 03:34:50 +08:00
|
|
|
</svg>
|
|
|
|
|
</div>
|
2026-02-18 17:38:10 +08:00
|
|
|
<div class="loop-label">
|
|
|
|
|
检查
|
|
|
|
|
</div>
|
2026-02-06 03:34:50 +08:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="loop-description">
|
2026-02-18 17:38:10 +08:00
|
|
|
<div
|
|
|
|
|
class="step"
|
|
|
|
|
:class="{ active: currentStep === 1 }"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
<span class="step-num">1</span>
|
|
|
|
|
<span class="step-text">执行调用栈中的同步代码</span>
|
|
|
|
|
</div>
|
2026-02-18 17:38:10 +08:00
|
|
|
<div
|
|
|
|
|
class="step"
|
|
|
|
|
:class="{ active: currentStep === 2 }"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
<span class="step-num">2</span>
|
|
|
|
|
<span class="step-text">执行所有微任务 (microtasks)</span>
|
|
|
|
|
</div>
|
2026-02-18 17:38:10 +08:00
|
|
|
<div
|
|
|
|
|
class="step"
|
|
|
|
|
:class="{ active: currentStep === 3 }"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
<span class="step-num">3</span>
|
|
|
|
|
<span class="step-text">渲染 UI (如果需要)</span>
|
|
|
|
|
</div>
|
2026-02-18 17:38:10 +08:00
|
|
|
<div
|
|
|
|
|
class="step"
|
|
|
|
|
:class="{ active: currentStep === 4 }"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
<span class="step-num">4</span>
|
|
|
|
|
<span class="step-text">执行宏任务 (macrotask)</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 任务队列 -->
|
|
|
|
|
<div class="section">
|
2026-02-18 17:38:10 +08:00
|
|
|
<div class="section-title">
|
|
|
|
|
任务队列
|
|
|
|
|
</div>
|
2026-02-06 03:34:50 +08:00
|
|
|
|
|
|
|
|
<div class="queue microtask-queue">
|
2026-02-18 17:38:10 +08:00
|
|
|
<div class="queue-title">
|
|
|
|
|
微任务队列 (Microtasks)
|
|
|
|
|
</div>
|
2026-02-06 03:34:50 +08:00
|
|
|
<div class="queue-items">
|
2026-02-18 17:38:10 +08:00
|
|
|
<div
|
|
|
|
|
v-for="(task, idx) in microtasks"
|
|
|
|
|
:key="task.id"
|
|
|
|
|
class="queue-item microtask"
|
|
|
|
|
:style="{ animationDelay: idx * 0.1 + 's' }"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
<span class="task-name">{{ task.name }}</span>
|
|
|
|
|
<span class="task-priority">高优先级</span>
|
|
|
|
|
</div>
|
2026-02-18 17:38:10 +08:00
|
|
|
<div
|
|
|
|
|
v-if="microtasks.length === 0"
|
|
|
|
|
class="empty-queue"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
队列为空
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="queue macrotask-queue">
|
2026-02-18 17:38:10 +08:00
|
|
|
<div class="queue-title">
|
|
|
|
|
宏任务队列 (Macrotasks)
|
|
|
|
|
</div>
|
2026-02-06 03:34:50 +08:00
|
|
|
<div class="queue-items">
|
2026-02-18 17:38:10 +08:00
|
|
|
<div
|
|
|
|
|
v-for="(task, idx) in tasks"
|
|
|
|
|
:key="task.id"
|
|
|
|
|
class="queue-item macrotask"
|
|
|
|
|
:style="{ animationDelay: idx * 0.15 + 's' }"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
<span class="task-name">{{ task.name }}</span>
|
|
|
|
|
<span class="task-type">{{ task.type }}</span>
|
|
|
|
|
</div>
|
2026-02-18 17:38:10 +08:00
|
|
|
<div
|
|
|
|
|
v-if="tasks.length === 0"
|
|
|
|
|
class="empty-queue"
|
|
|
|
|
>
|
2026-02-06 03:34:50 +08:00
|
|
|
队列为空
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref, computed } from 'vue'
|
|
|
|
|
|
|
|
|
|
const isRunning = ref(false)
|
|
|
|
|
const simulationSpeed = ref(2)
|
|
|
|
|
const currentStep = ref(1)
|
|
|
|
|
const callStack = ref([])
|
|
|
|
|
const microtasks = ref([])
|
|
|
|
|
const tasks = ref([])
|
|
|
|
|
let taskIdCounter = 1
|
|
|
|
|
let microtaskIdCounter = 1
|
|
|
|
|
|
|
|
|
|
function addTask() {
|
|
|
|
|
if (tasks.value.length >= 10) return
|
|
|
|
|
const types = ['setTimeout', 'setInterval', 'I/O', 'DOM事件']
|
|
|
|
|
tasks.value.push({
|
|
|
|
|
id: taskIdCounter++,
|
|
|
|
|
name: `任务 ${taskIdCounter - 1}`,
|
|
|
|
|
type: types[Math.floor(Math.random() * types.length)]
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addMicrotask() {
|
|
|
|
|
if (microtasks.value.length >= 5) return
|
|
|
|
|
microtasks.value.push({
|
|
|
|
|
id: microtaskIdCounter++,
|
|
|
|
|
name: `微任务 ${microtaskIdCounter - 1}`
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function startSimulation() {
|
|
|
|
|
if (isRunning.value) return
|
|
|
|
|
|
|
|
|
|
// 确保有任务
|
|
|
|
|
if (tasks.value.length === 0) {
|
|
|
|
|
addTask()
|
|
|
|
|
addTask()
|
|
|
|
|
}
|
|
|
|
|
if (microtasks.value.length === 0) {
|
|
|
|
|
addMicrotask()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isRunning.value = true
|
|
|
|
|
currentStep.value = 1
|
|
|
|
|
|
|
|
|
|
// 模拟执行过程
|
|
|
|
|
runSimulationStep()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function runSimulationStep() {
|
|
|
|
|
if (!isRunning.value) return
|
|
|
|
|
|
|
|
|
|
// 模拟步骤执行
|
|
|
|
|
const speed = 6 - simulationSpeed.value // 转换为延迟
|
|
|
|
|
const delay = speed * 200
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
if (!isRunning.value) return
|
|
|
|
|
|
|
|
|
|
currentStep.value = (currentStep.value % 4) + 1
|
|
|
|
|
|
|
|
|
|
// 更新调用栈
|
|
|
|
|
updateCallStack()
|
|
|
|
|
|
|
|
|
|
// 消耗任务
|
|
|
|
|
if (currentStep.value === 2 && microtasks.value.length > 0) {
|
|
|
|
|
microtasks.value.shift()
|
|
|
|
|
} else if (currentStep.value === 4 && tasks.value.length > 0) {
|
|
|
|
|
tasks.value.shift()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查是否完成
|
|
|
|
|
if (tasks.value.length === 0 && microtasks.value.length === 0) {
|
|
|
|
|
isRunning.value = false
|
|
|
|
|
callStack.value = []
|
|
|
|
|
} else {
|
|
|
|
|
runSimulationStep()
|
|
|
|
|
}
|
|
|
|
|
}, delay)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateCallStack() {
|
|
|
|
|
const stack = []
|
|
|
|
|
|
|
|
|
|
switch (currentStep.value) {
|
|
|
|
|
case 1:
|
|
|
|
|
stack.push({ name: 'main()', line: 1 })
|
|
|
|
|
stack.push({ name: 'executeSync()', line: 15 })
|
|
|
|
|
break
|
|
|
|
|
case 2:
|
|
|
|
|
stack.push({ name: 'main()', line: 1 })
|
|
|
|
|
stack.push({ name: 'processMicrotask()', line: 25 })
|
|
|
|
|
break
|
|
|
|
|
case 3:
|
|
|
|
|
stack.push({ name: 'main()', line: 1 })
|
|
|
|
|
stack.push({ name: 'render()', line: 35 })
|
|
|
|
|
break
|
|
|
|
|
case 4:
|
|
|
|
|
stack.push({ name: 'main()', line: 1 })
|
|
|
|
|
stack.push({ name: 'processMacrotask()', line: 45 })
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
callStack.value = stack
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function reset() {
|
|
|
|
|
isRunning.value = false
|
|
|
|
|
currentStep.value = 1
|
|
|
|
|
callStack.value = []
|
|
|
|
|
microtasks.value = []
|
|
|
|
|
tasks.value = []
|
|
|
|
|
taskIdCounter = 1
|
|
|
|
|
microtaskIdCounter = 1
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.demo-container {
|
|
|
|
|
padding: 20px;
|
|
|
|
|
background: #f5f7fa;
|
2026-02-14 20:23:34 +08:00
|
|
|
border-radius: 6px;
|
2026-02-06 03:34:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
h4 {
|
|
|
|
|
margin: 0 0 16px 0;
|
|
|
|
|
color: #303133;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.controls {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.event-loop-container {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: 1fr 1.2fr 1fr;
|
|
|
|
|
gap: 16px;
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section {
|
|
|
|
|
background: white;
|
2026-02-14 20:23:34 +08:00
|
|
|
border-radius: 6px;
|
2026-02-06 03:34:50 +08:00
|
|
|
padding: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-title {
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #303133;
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
border-bottom: 1px solid #e4e7ed;
|
|
|
|
|
padding-bottom: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stack-container {
|
|
|
|
|
min-height: 200px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stack-frame {
|
|
|
|
|
background: #f5f7fa;
|
|
|
|
|
border: 1px solid #e4e7ed;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
margin-bottom: 4px;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stack-frame.active {
|
|
|
|
|
background: #ecf5ff;
|
|
|
|
|
border-color: #409eff;
|
|
|
|
|
animation: pulse 1s infinite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes pulse {
|
|
|
|
|
0%, 100% {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
50% {
|
|
|
|
|
opacity: 0.7;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.frame-name {
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #303133;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.frame-line {
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
color: #909399;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.empty-stack {
|
|
|
|
|
text-align: center;
|
|
|
|
|
color: #909399;
|
|
|
|
|
padding: 40px;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.event-loop {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loop-container {
|
|
|
|
|
flex: 1;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
padding: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loop-arrow {
|
|
|
|
|
width: 120px;
|
|
|
|
|
height: 120px;
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loop-arrow.rotating .loop-svg {
|
|
|
|
|
animation: rotate 2s linear infinite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes rotate {
|
|
|
|
|
from {
|
|
|
|
|
transform: rotate(0deg);
|
|
|
|
|
}
|
|
|
|
|
to {
|
|
|
|
|
transform: rotate(360deg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loop-circle {
|
|
|
|
|
animation: dash 2s linear infinite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes dash {
|
|
|
|
|
0% {
|
|
|
|
|
stroke-dashoffset: 200;
|
|
|
|
|
}
|
|
|
|
|
100% {
|
|
|
|
|
stroke-dashoffset: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loop-label {
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #409eff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loop-description {
|
|
|
|
|
margin-top: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.step {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
padding: 8px;
|
|
|
|
|
margin-bottom: 4px;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.step.active {
|
|
|
|
|
background: #ecf5ff;
|
|
|
|
|
border-left: 3px solid #409eff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.step-num {
|
|
|
|
|
width: 20px;
|
|
|
|
|
height: 20px;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
background: #dcdfe6;
|
|
|
|
|
color: #606266;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.step.active .step-num {
|
|
|
|
|
background: #409eff;
|
|
|
|
|
color: white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.step-text {
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
color: #606266;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.step.active .step-text {
|
|
|
|
|
color: #303133;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.queue {
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.queue-title {
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #606266;
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 4px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.queue-title::before {
|
|
|
|
|
content: '';
|
|
|
|
|
width: 8px;
|
|
|
|
|
height: 8px;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.microtask-queue .queue-title::before {
|
|
|
|
|
background: #f56c6c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.macrotask-queue .queue-title::before {
|
|
|
|
|
background: #e6a23c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.queue-items {
|
|
|
|
|
min-height: 60px;
|
|
|
|
|
background: #f5f7fa;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
padding: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.queue-item {
|
|
|
|
|
background: white;
|
|
|
|
|
border: 1px solid #e4e7ed;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
margin-bottom: 4px;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
animation: slideIn 0.3s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes slideIn {
|
|
|
|
|
from {
|
|
|
|
|
opacity: 0;
|
|
|
|
|
transform: translateX(-20px);
|
|
|
|
|
}
|
|
|
|
|
to {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
transform: translateX(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.queue-item.microtask {
|
|
|
|
|
border-left: 3px solid #f56c6c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.queue-item.macrotask {
|
|
|
|
|
border-left: 3px solid #e6a23c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.task-name {
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
color: #303133;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.task-type {
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
color: #909399;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.empty-queue {
|
|
|
|
|
text-align: center;
|
|
|
|
|
color: #909399;
|
|
|
|
|
padding: 20px;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 1024px) {
|
|
|
|
|
.event-loop-container {
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|