每个人都知道JavaScript是一种单线语言,一次只有一件事。
至于为什么它是一个线程,它实际上与使用相关。由于JavaScript作为Goggles脚本语言,其主要目的是与用户进行交互并操作DOM。如果是多线程,则该线程删除一个线程DOM,另一个线程添加了此DOM的内容或修改。此时如何渲染?
因此,从诞生开始,JavaScript是单个线程,是该语言的核心功能。
当然,HTML5提出了Web Worker标准,以允许JavaScript脚本创建多个线程,但是子线程由主线程控制,无法操作。该标准不会改变单个线程的本质。
一个线程的特征将引起一些问题,例如:当我们请求服务器接口时,该页面在等待数据返回之前就无法操作,并且会有假死亡的状态。但实际上,我们确实做到了没有遇到这种情况。
这是因为我们通过异步(非屏体)执行模式解决了单线线程的问题。
同步(阻止)
当涉及异步时,我们自然可以考虑同步(阻止)。
什么是同步?好像我们要排队核酸。Dabai通过排队的顺序进行了测试。背后的人只能等待前面的人们检测到它以检测到它。
上述代码将按顺序执行,当时它将输入循环。大约2秒钟后,它将跳出循环,然后执行最后一行打印行。这导致了阻塞的出现。封锁的特征是:遇到时间 - 耗时代码片段,消耗时间的代码已完成继续代码继续执行。
异步(非块)
异步和同步,它不会阻止程序的操作。当程序运行时,当遇到异步模式的代码时,引擎将挂起异步任务并首先跳过,然后继续执行非 -特定代码。执行同步代码时,刚刚悬挂的异步代码按特定顺序执行。我们可以查看以下代码:
该程序将首先输出,然后等待2秒钟输出。由于程序执行时,当我遇到SetteMeTimeout时,它不会直接执行内部回调函数。取而代之的是,首先悬挂内部函数,继续执行以下同步代码,在执行同步代码后,请等待大约2秒钟,然后回头回去。
可以想象异步。您必须去超市购买食物。您无法想到做一次菜一次买菜。列出,但列出了菜肴。
JavaScript的运行顺序是严格的一个线程异步模式:前面的同步,在后面的异步。异步任务需要等待在执行之前执行当前同步任务。
尽管游客是由单个线程执行以执行JavaScript代码的,但游客有多个线程,可以帮助操作实现单个线程异步模型。
在运行JavaScript代码的过程中,实际执行实际执行程序时只有一个活动线程,并且通过多线程切换来实现同步异步。
以上段线程可以汇总到两个线程中:
在上面,我们将线程分为主线程和工作线程。当主线程的代码运行时,当同步代码运行时,我们将其放在执行堆栈中以execute.rise。
执行堆栈负责执行代码,遵循高级和输出的原理,当执行功能时,它将按顺序从外部到内部运行。对象的数据可以存储在堆内存中。
悬挂在工作线程中的任务都是异步任务,例如网络请求,定时功能,交互式事件等。
当执行堆栈中的任务完全执行时,执行堆栈是明确的,并且事件周期将开始工作。它将检测到消息队列中是否有任务。插入已过期的异步任务到达消息队列中。如果需要执行一个任务,则将按照反盗窃执行堆栈执行,按先进的首先,直到消息队列也为空。
如上所述,定义了5个函数。执行后,主要程序首先遇到了两个异步任务。在0秒后,F5和F6在1秒后执行。键(即将其放入工作线中),然后继续下面的代码。
然后,F1函数首先输入执行堆栈执行,并从堆栈中执行F1函数。
然后将F2函数放入执行堆栈执行中,然后将F2函数从堆栈中执行。
然后将F4函数放在执行堆栈执行中。执行F4函数时,发现F3函数将在内部执行。此时,将F3函数放在执行堆栈中以执行。
当主线程的同步代码完全执行时,此时,事件循环机制将起床并起作用,并继续从消息队列中读取是否需要执行任务。
下一步是执行异步任务。现在,我们有3个异步任务要执行,F5需要0秒,F6需要1秒,而打印123的任务也需要0秒。
尽管F5和打印123的任务时间相同,但F5的任务比打印123优先考虑工作线程,因此F5将优先考虑输入消息队列。
目前,事件周期机制发现消息队列中有一个任务,并且F5将在执行堆栈中取出以执行然后退出堆栈。
然后将123的任务打印到执行堆栈中。执行后,发现还有另一个异步任务打印1234,它将将此异步任务放入工作线程中,然后执行堆栈。
打印1234异步任务的所需时间为0秒,它将输入消息队列优先级,而不是F6,然后通过入射周期机制取出。
F6进入消息队列后,这也是如此。直到新闻队列为空。
执行堆栈:执行根据后续条目的顺序输入执行堆栈的任务,并在执行后离开堆栈。
工作线程:停滞异步任务悬挂,首先是在时间顺序上,到达哪个任务时间,然后将任务放在消息队列中。如果有相同的时间,请按顺序以输入工作线程顺序输入消息队列。
事件周期机制:执行同步代码后,任务是从消息队列(高级第一)中持续采取的,然后放入执行堆栈执行中。
从上面的内容可以看出,当我们运行单层函数时,堆栈执行该功能,然后将其从堆栈中销毁。turn.但是,如果有规范,则将堆栈框架堆叠在执行堆栈中。
如上所示,执行程序后,Test1将输入执行执行堆栈,然后执行执行时,发现Test1调用FN,FN,FN将传递。然后Test1将停止;
执行Test2时,您会发现Test3在Test2中调用,然后将Test3放置在堆栈顶部。
执行Test3后,它将退出堆栈,然后继续执行Test2。执行Test2后,它将退出堆栈,并将继续测试1。
目前,我们将考虑递归。递归函数可以被视为函数中的嵌入式n层执行。在执行过程中,将触发大量的堆栈框架积累,但是执行堆栈是深度。过多的堆栈框架积累会导致堆栈溢出。
根据不同的游客和JS发动机,堆栈的深度将有所不同。
如下所示,我们发现在递归11390次之后,提示它超过了堆栈的深度。
如何打破递归限制。目前,我们可以探索如何跨越示意力的限制?
我们之前说,在执行堆栈中执行程序后,事件周期机制将启用。如果执行堆栈在执行时遇到异步任务,则异步任务将悬挂在工作线程上,然后遵循以下内容-up -up -up -up -up代码将继续。
因此,我们可以将递归执行函数放在异步任务中吗?以这种方式,堆栈的堆栈不会累积堆栈框架。每次您仅从消息队列中删除任务时,递归调用的任务都放在工作线中,继续执行同步代码后继续执行以下同步代码,然后读取消息的queueThe queueThe queueThe queueThe queuether osynchronous任务中期到期的执行堆栈中,并反复。
针不戳,但不能保证操作速度。
在这一点上,至于宏任务和微任务,让我们稍后再谈谈!
原始:https://juejin.cn/post/7097518995620200485