0

0

JavaScript 中的事件循环与阻塞式 while 循环详解

花韻仙語

花韻仙語

发布时间:2026-02-01 16:18:01

|

671人浏览过

|

来源于php中文网

原创

JavaScript 中的事件循环与阻塞式 while 循环详解

本文深入解析为何 while(geti() === 1) { } 会导致程序无限卡死、“asd” 永不打印、promise 永不 resolve——根本原因在于 javascript 单线程 + 事件驱动模型下,同步阻塞循环会彻底垄断执行权,使 settimeout、变量更新等异步/后续操作完全无法介入。

JavaScript 是单线程、事件驱动的语言。所有同步代码(如函数调用、循环、赋值)都在主线程上连续、阻塞式执行,直到该段代码彻底返回,控制权才会交还给事件循环(Event Loop)。而 setTimeout、Promise 回调、DOM 事件等异步任务,都必须排队等待事件循环调度——它们绝不会中断正在运行的同步代码。

在你的示例中:

let i = 1;

function getI() {
    return i;
}

new Promise(resolve => {
    while(getI() === 1) {
        // ❌ 空循环:无 await、无 yield、无异步让出
        // 主线程被永久占用,事件循环被冻结
    }
    console.log('asd'); // ← 永远不会执行
    resolve();
});

i = 2; // ← 这行在 Promise 构造器之后,但因前一个 Promise 的 while 死循环未退出,JS 引擎卡死在此处,这行甚至来不及执行!

setTimeout(() => i = 3, 1500); // ← 回调被压入宏任务队列,但事件循环永不启动 → 永不执行

new Promise(resolve => {
    i = 4;
    resolve();
}); // ← 同样被阻塞,构造器内部的同步代码无法开始

关键机制链如下:

  1. while(getI() === 1) 是纯同步、无暂停的忙等待(busy-wait)
    它反复调用 getI() 并检查 i === 1,但 i 在循环体内从未被修改;外部对 i 的赋值(如 i = 2)发生在该循环之后,而循环又永不结束 → 形成死循环。

  2. 事件循环被完全阻塞
    setTimeout 的回调被注册进宏任务队列(macrotask queue),但事件循环只有在当前调用清空后才会轮询队列。由于 while 循环永不退出,调用栈永远非空 → 宏任务永远得不到执行机会。

    立即学习Java免费学习笔记(深入)”;

    VidAU
    VidAU

    VidAU AI 是一款AI驱动的数字人视频创作平台,旨在简化视频内容创作流程

    下载
  3. Promise 构造器是同步执行的
    new Promise(fn) 会立即、同步调用传入的 fn。因此 while 循环在 Promise 创建时就已启动,并独占主线程。

✅ 正确解法:用异步方式“等待条件”,主动让出控制权
避免阻塞,改用 Promise + setTimeout 或 async/await 实现轮询(polling):

function waitForI(value, timeout = 5000) {
    return new Promise((resolve, reject) => {
        const start = Date.now();
        const check = () => {
            if (getI() === value) {
                resolve();
            } else if (Date.now() - start > timeout) {
                reject(new Error(`Timeout waiting for i === ${value}`));
            } else {
                // ✅ 主动让出控制权,允许其他任务执行
                setTimeout(check, 0);
            }
        };
        check();
    });
}

// 使用示例:
waitForI(2)
    .then(() => console.log('asd'))
    .catch(console.error);

i = 2; // 现在可正常触发

⚠️ 注意事项:

  • 不要使用 while (condition) {} 等待状态变化——这是反模式;
  • await 仅在 async 函数内有效,且需配合真正异步操作(如 Promise);
  • 浏览器中长时间同步执行还会触发“页面无响应”警告;Node.js 中则导致整个进程卡死;
  • 若需高性能轮询,可结合 requestIdleCallback(浏览器)或 setImmediate(Node.js)优化调度。

总结:JavaScript 的“非阻塞”特性不等于自动并发,而是依赖开发者主动通过异步 API(Promise、setTimeout、await)将长任务拆解并让出主线程。理解事件循环与调用栈的关系,是写出健壮、响应式 JS 代码的基石。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

98

2023.09.25

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

399

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

575

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

546

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

546

2023.08.10

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

516

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

246

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

361

2023.08.03

go语言 注释编码
go语言 注释编码

本专题整合了go语言注释、注释规范等等内容,阅读专题下面的文章了解更多详细内容。

30

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.4万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.6万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号