js中的同步和异步

一、单线程

JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事,需要排队执行。如果前面的A任务会花费大量的时间,就会导致后面的B任务停止执行,知道A执行完才会执行B。如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据,进行大量计算),不得不等着结果出来,再往下执行。

console.log(Date.now());
console.log('===========');
console.log(Date.now());
for (let i = 0; i < 100000000; i++) {
}
console.log('=====');
console.log(Date.now());
        
        //输出
        1644333664879
        ===========
        1644333664879
        =====
        1644333664922

 前两个时间戳因为代码执行很快输出的时间戳相同,相隔一个for循环后,第三个时间戳输出与前两个相差较大相差43毫秒。

 

这个时候JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。

二、同步和异步

为了防止主线程的不阻塞,异步方案产生。 所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是:不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。任务队列其实是一个先进先出的数据结构

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。

console.log(Date.now());
console.log('===========');
console.log(Date.now());
setTimeout(() => {
for (let i = 0; i < 100000000; i++) {
            }
console.log('异步2s');
console.log(Date.now());
        }, 2000)
setTimeout(() => {
for (let i = 0; i < 100000000; i++) {
            }
console.log('异步1s');
console.log(Date.now());
        }, 1000)
console.log('=====');
console.log(Date.now());
     
 //输出
1644334680961
===========
 1644334680961
 =====
 1644334680961
 异步1s
1644334682005
异步2s
1644334683012

用定时器(异步操作)将for循环包裹起来,使for循环成为异步操作,不进入主线程。进入队列任务开始执行。使三个时间戳的输出相近,不会因为for循环而等待大量时间。

异步1s输出的时间戳和前一个同步时间戳相差1044毫秒(减去for循环的43毫秒可看作1000毫秒了),异步2s和异步1s相差1007毫秒。

意味着异步任务一进入队列任务就开始执行,执行完成后会在任务队列放置一个结果的事件。当同步认证执行完成后,会进入任务队列读取已经执行完成的异步任务的回调函数结果并输出。

单线程从从任务队列中读取任务是不断循环的,每次栈被清空后,都会在任务队列中读取新的任务,如果没有任务,就会等到,直到有新的任务,这就叫做任务循环,因为每个任务都是由一个事件触发的,因此也叫作事件循环

三、异步回调函数的理解

普通函数是从上到下执行的,而异步函数你是不知道他在什么时候会执行完,但是你有想在他执行完的时候处理结果怎么办?使用回调函数,异步任务的回调函数会在这个异步任务执行完的时候进行调用,进行处理异步任务的数据。

所以说普遍的异步任务都会有一个回调函数,进行数据的处理。

posted @   铜须的编程生活  阅读(3243)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示