摘要:事件循环背景是一门单线程非阻塞的脚本语言,单线程意味着,代码在执行的任何时候,都只有一个主线程来处理所有的任务。在意识到该问题之际,新特性中的可以让成为一门多线程语言,但实际开发中使用存在着诸多限制。这个地方被称为执行栈。
事件循环(Event Loop) 背景
JavaScript是一门单线程非阻塞的脚本语言,单线程意味着,JavaScript代码在执行的任何时候,都只有一个主线程来处理所有的任务。而非阻塞则是当代码需要进行一项异步任务(无法立刻返回结果,需要花一定时间才能返回的任务,如I/O事件)的时候,主线程会挂起(pending)这个任务,然后在异步任务返回结果的时候再根据一定规则去执行相应的回调。
在意识到该问题之际,html5新特性中的web worker可以让JavaScript成为一门多线程语言,但实际开发中使用web worker存在着诸多限制。
思考一下这段代码的结果?
显然,同步函数是由上至下的执行顺序
因为setTimeout是异步函数,js执行机制是先将同步函数执行完毕,再执行异步函数
当javascript代码执行的时候会将不同的变量存于内存中的不同位置:堆(heap)和栈(stack)中来加以区分。其中,堆里存放着一些对象。而栈中则存放着一些基础类型变量以及对象的指针。如下:
当我们调用一个方法的时候,js会生成一个与这个方法对应的执行环境(context),又叫执行上下文。这个执行环境中存在着这个方法的私有作用域,上层作用域的指向,方法的参数,这个作用域中定义的变量以及这个作用域的this对象。 而当一系列方法被依次调用的时候,因为js是单线程的,同一时间只能执行一个方法,于是这些方法被排队在一个多带带的地方。这个地方被称为执行栈。
当脚本第一次执行的时候,js引擎会解析这段代码,并将其中的同步代码按照执行顺序加入执行栈中,然后从头开始执行。如果当前执行的是一个方法,那么js会向执行栈中添加这个方法的执行环境,然后进入这个执行环境继续执行其中的代码。当这个执行环境中的代码 执行完毕并返回结果后,js会退出这个执行环境并把这个执行环境销毁,回到上一个方法的执行环境。这个过程反复进行,直到执行栈中的代码全部执行完毕。
在异步函数中,可以细分为两种任务,宏任务与微任务。
宏任务有以下几种:
①I/O
②setTimeout
③setInterval
④setImmediate
⑤requestAnimationFrame
微任务有以下几种:
①process.nextTick
②MutationObserver
③Promise.then catch finally
当异步函数中同时存在微任务和宏任务的时候,先执行完微任务,再执行宏任务
浏览器中的事件循环机制就是js在执行代码时,由上至下遍历,优先执行同步函数,在遇到异步函数的时候,将该任务放置执行栈;当任务队列中没有同步函数之后便开始执行执行栈中的异步函数,优先执行微任务,后执行宏任务。
js执行顺序: 同步函数 -> 微任务 -> 宏任务
console.log("script start") setTimeout(function(){ console.log("settimeout") }) console.log("script end") // 输出顺序:script start->script end->settimeout
这个很简单,setTimeout中的语句会进入宏任务,后置执行。
promiseconsole.log("script start") let promise1 = new Promise(function (resolve) { console.log("promise1") resolve() console.log("promise1 end") }).then(function () { console.log("promise2") }) setTimeout(function(){ console.log("settimeout") }) console.log("script end") // 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout
两个要点:
①promise中的then函数中代码会进入微任务
②promise中的resolve只是更改promise的状态,因此后面的语句会继续执行。
async function async1(){ console.log("async1 start"); await async2(); console.log("async1 end") } async function async2(){ console.log("async2") } console.log("script start"); async1(); console.log("script end") // 输出顺序:script start->async1 start->async2->script end->async1 end
async函数表示函数里面可能会有异步方法,await后面跟一个表达式,async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行
综合测试async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } async function async2() { console.log("async2"); } console.log("script start"); setTimeout(function() { console.log("setTimeout"); }, 0) async1(); new Promise(function(resolve) { console.log("promise1"); resolve(); }).then(function() { console.log("promise2"); }); console.log("script end");
这题不公布答案,自行答题。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/101946.html
摘要:如果没有其他异步任务要处理比如到期的定时器,会一直停留在这个阶段,等待请求返回结果。执行的执行事件关闭请求的,例如事件循环的每一次循环都需要依次经过上述的阶段。因此,才会早于执行。 showImg(https://segmentfault.com/img/bVbnY76); 概念 同步任务(Synchronous) 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务 ...
摘要:以多线程的形式,允许单个任务分成不同的部分进行运行。提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。主线程会不断的重复上诉过程。 众所周知,js是单线程的,说到线程,我们首先来仔细辨析一下线程和进程的知识。 一、进程与线程 阮一峰老师的一篇文章写的很好 cpu会给当前进程分配资源,进程是资源分配的最小单位,进程的资源会分配给线程使用,线程是C...
摘要:关于循环和闭包当循环和闭包结合在一起时,经常会产生让初学者觉得匪夷所思的问题。闭包是一把双刃剑是比较难以理解和掌握的部分,它十分强大,却也有很大的缺陷,如何使用它完全取决于你自己。 在谈闭包之前,我们首先要了解几个概念: 什么是函数表达式? 与函数声明有何不同? JavaScript查找标识符的机制 JavaScript的作用域是词法作用域 JavaScript的垃圾回收机制 先来...
摘要:引言一直对浏览器的进程线程的运行一无所知,经过一次的刷刷刷相关的博客之后,对其有了初步的了解,是时候该总结一波了。浏览器内的进程知道了进程与线程之间的关系之后,下面是浏览器与进程的关系了。 引言 一直对浏览器的进程、线程的运行一无所知,经过一次的刷刷刷相关的博客之后,对其有了初步的了解,是时候该总结一波了。 进程、线程之间的关系 一个进程有一个或多个线程,线程之间共同完成进程分配下来的...
摘要:事件简介事件是合成事件,所有事件都自动绑定到最外层上。支持事件的冒泡机制,我们可以使用和来中断它。这样做简化了事件处理和回收机制,效率也有很大提升。事件类型合成事件的事件类型是原生事件类型的一个子集。 React事件简介 React事件是合成事件,所有事件都自动绑定到最外层上。因为Virtual DOM 在内存中是以对象的形式存在的,所以React 基于 Virtual DOM 实现了...
阅读 1845·2021-11-15 11:39
阅读 1027·2020-12-03 17:06
阅读 682·2019-12-27 11:42
阅读 3247·2019-08-30 13:59
阅读 1436·2019-08-26 13:22
阅读 3267·2019-08-26 12:15
阅读 2453·2019-08-26 10:22
阅读 1540·2019-08-23 18:40