LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

为什么我的JavaScript异步代码总是不按顺序执行?

zhenglin
2026年8月4日 10:33 本文热度 39

引言

作为JavaScript开发者,你可能经常遇到这样的情况:明明代码是按照顺序写的,但执行结果却与预期不符。这种"不按顺序执行"的现象,实际上是JavaScript异步编程模型的核心特性。本文将深入剖析JavaScript的异步机制,解释为什么代码不按书写顺序执行,并探讨如何正确理解和控制异步代码的执行流程。

主体

1. JavaScript的单线程与事件循环模型

JavaScript是单线程语言,这意味着它一次只能执行一个任务。为了处理I/O操作、网络请求等耗时任务而不阻塞主线程,JavaScript采用了**事件循环(Event Loop)**机制。

console.log('1');

setTimeout(() => console.log('2'), 0);

console.log('3');

// 输出顺序:1, 3, 2

这个经典示例展示了即使setTimeout的延迟为0,其回调函数也会在同步代码执行完毕后才会运行。这是因为:

  1. 所有同步代码进入调用栈立即执行

  2. 异步回调被放入任务队列

  3. 事件循环只有当调用栈为空时,才会从任务队列中取出任务执行


2. 宏任务与微任务

JavaScript异步任务分为两种类型:

  • 宏任务(Macrotask):

  • setTimeout/setInterval

  • I/O操作

  • UI渲染

  • setImmediate(Node.js)

  • 微任务(Microtask):*

  • Promise.then/catch/finally

  • MutationObserver

  • process.nextTick(Node.js)


事件循环的执行顺序规则:

  1. 执行一个宏任务(初始为脚本整体)

  2. 执行所有可用的微任务

  3. 渲染UI(浏览器环境)

  4. 开始下一个宏任务

console.log('script start'); // 宏任务1


setTimeout(function() {

  console.log('setTimeout'); // 宏任务2

}, 0);


Promise.resolve().then(function() {

  console.log('promise1'); // 微任务1

}).then(function() {

  console.log('promise2'); // 微任务2

});


console.log('script end'); // 宏任务1继续

/* 输出顺序:

script start

script end

promise1

promise2

setTimeout

* /

3. 常见的异步执行困惑场景

3.1 循环中的异步

for (var i = 0; i < 3; i++) {

  setTimeout(() => console.log(i), 0);

}

// 输出:3, 3, 3

这里因为var没有块级作用域,所有回调共享同一个i。解决方案:

// 使用let创建块级作用域

for (let i = 0; i < 3; i++) {

  setTimeout(() => console.log(i), 0);

}


// 或使用闭包

for (var i = 0; i < 3; i++) {

  (function(j) {

    setTimeout(() => console.log(j), 0);

  })(i);

}

3.2 Promise链的执行顺序

Promise.resolve()

  .then(() => console.log(1))

  .then(() => console.log(2));


Promise.resolve()

  .then(() => console.log(3))

  .then(() => console.log(4));

// 可能输出:1, 3, 2, 4

虽然每个Promise链是顺序的,但不同Promise链之间是交替执行的。

4. 控制异步执行顺序的方法

4.1 Promise链

function asyncTask1() {

  return new Promise(resolve => {

    setTimeout(() => {

      console.log('Task 1');

      resolve();

    }, 1000);

  });

}


function asyncTask2() {

  return new Promise(resolve => {

    setTimeout(() => {

      console.log('Task 2');

      resolve();

    }, 500);

  });

}


asyncTask1()

  .then(() => asyncTask2())

  .then(() => console.log('All tasks completed'));

4.2 async/await

async function runTasks() {

  await asyncTask1();

  await asyncTask2();

  console.log('All tasks completed');

}

runTasks();

4.3 Promise.all和Promise.race

当需要并行执行但需要控制完成顺序时:

// 并行执行,按数组顺序返回

Promise.all([asyncTask1(), asyncTask2()])

  .then(() => console.log('All done'));


// 任意一个完成即继续

Promise.race([asyncTask1(), asyncTask2()])

  .then(() => console.log('One of them is done'));

5. 深入理解任务队列

JavaScript运行环境维护着多个队列:

  1. 脚本执行队列:初始的同步代码

  2. 微任务队列:Promise回调等

  3. 宏任务队列:setTimeout等

  4. 渲染队列:requestAnimationFrame等

  5. IO队列:文件读写、网络请求等


当事件循环运行时:

  • 检查微任务队列直到清空

  • 执行一个宏任务

  • 再次检查微任务队列

  • 可能执行渲染


6. Node.js与浏览器环境的差异

Node.js中引入了process.nextTick,它比Promise的微任务优先级更高:

Promise.resolve().then(() => console.log('promise'));

process.nextTick(() => console.log('nextTick'));

// 输出:nextTick, promise

此外,Node.js还有setImmediate,它与setTimeout(fn, 0)类似但处于不同阶段。


7. 性能考量与最佳实践

  1. 避免阻塞事件循环:长时间运行的同步代码会阻止异步回调执行

  2. 合理使用微任务:过多微任务会导致宏任务饥饿

  3. 错误处理:Promise链中未被捕获的错误可能静默失败

  4. 内存泄漏:未清除的定时器和事件监听器是常见内存泄漏源

// 不好的实践

function leaky() {

  setInterval(() => {

    // 长期运行的任务

  }, 1000);

}


// 好的实践

function safe() {

  const interval = setInterval(() => {

    // 任务完成后清除

    clearInterval(interval);

  }, 1000);

}


总结

JavaScript异步代码"不按顺序执行"的特性是其事件驱动架构的核心所在。理解事件循环、任务队列和微任务机制是掌握JavaScript异步编程的关键。通过Promise、async/await等现代语法,我们可以更好地控制异步流程,但必须牢记它们背后的执行模型。

正确的异步编程不仅需要理解执行顺序,还需要考虑错误处理、性能优化和资源管理。随着对JavaScript并发模型理解的深入,你将能够编写出既高效又可靠的异步代码,充分利用JavaScript非阻塞I/O的优势。



阅读原文:点击这里


该文章在 2026/8/4 10:34:14 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-9  粤公网安备44030602007207号