js的异步执行

1.浏览器是单线程执行JavaScript代码的,但是浏览器实际上是以多个线程协助操作来实现单线程异步模型的,具体线程组成如下: 

1.GUI 渲染进程

2.JavaScript 引擎线程

3.事件触发线程

4.定时器触发线程

5.http 请求线程

6.其他线程

所以我们分析时,将上面的细分线程归纳为下列两条线程:

1.【主线程】:这个线程用来执行页面的渲染,JavaScript 代码的运行,事件的触发等等。

2.【工作线程】:这个线程是在幕后工作的,用来处理异步任务的执行来实现非阻塞的运行模式。

2.JavaScript 的运行模型

 上图是运行时的一个工作流程和内存划分的简要描述,我们根据图中可以 得知主线程就是我们JavaScript 执行代码的线程,主线程代码在运行时,会按照同步 和异步代码将其分成两个去处,如果是同步代码执行,就会直接将该任务放在一个 叫做"函数执行栈”的空间进行执行,执行栈是典型的【栈结构】(先进后出),程序 在运行的时候会将同步代码按顺序入栈,将异步代码放到【工作线程】中暂时挂 起,【工作线程】中保存的是定时任务函数、js 的交互事件、js 的网络请求等耗时操 作。当【主线程】将代码块筛选完毕后,进入执行栈的函数会按照从外到内的顺序 依次运行,运行中涉及到的对象数据是在堆内存中进行保存和管理的。当执行栈内 的任务全部执行完毕后,执行栈就会清空。执行栈清空后,“事件循环”就会工作, "事件循环"会检测【任务队列】中是否有要执行的任务,那么这个任务队列的任务来 源就是工作线程,程序运行期间,工作线程会把到期的定时任务、返回数据的 http 任务等【异步任务】按照先后顺序插入到【任务队列】中,等执行栈清空后,事件 循环会访问任务队列,将任务队列中存在的任务,按顺序(先进先出)放在执行栈 中继续执行,直到任务队列清空。

回调函数本身是同步代码。

JavaScript中的回 调函数结构,默认是同步的结构,由于JavaScript单线程异步模型的规则,如果想要编写异步的代码,必须 使用回调嵌套的形式才能实现,所以回调函数结构不一定是异步代码,但是异步代码一定是回调函数结构。

分析了对象结构和状态后,我们了解了Promise的异步回调部分如何执行,取决于我们在初始化函数中的操 作,并且初始化函数中一旦调用了resolve后面再执行reject也不会影响then执行,catch也不会执行,反之同 理。而在初始化回调函数中,如果不执行任何操作,那么premise的状态就仍然是pending,所有注册的回调 函数都不会执行。

根据现象我们可以分析出链式调用的基本形式(极其重要): 1 .只要有then。并且触发了resplve,整个链条就会执行到结尾,这个过程中的第一个回调函数的参数是 resolve传入的值 2 .后续每个函数都可以使用return返回一个结果,如果没有返回结果的话下一个then中回调函数的参数就 是 undefined 3 .返回结果如果是普通变量,那么这个值就是下一个then中回调函数的参数 4 .如果返回的是一个Promise对象,那么这个Promise对象resolve的结果会变成下一次then中回调的函数 的参数(所以可以直接理解为,返回Promise对象时,下一个then就是该对象的then) 5 .如果then中传入的不是函数或者未传值,Promise链条并不会中断then的链式调用,并且在这之前最后 一次的返回结果,会直接进入离它最近的正确的then中的回调函数作为参数

链式调用可以中断吗?答案是肯定的,我们有两种形式可以让.then的链条中断,如果中断还会触发一 次.catch的执行。查阅下面的案例学习:

<script>
var p = new Promise(function(resolvez
reject){
resolve ('我是Promise的值’)
})
console.log(p)
p.then(function(res){
console.log(res)
}). then(function(res]{ >
//有两种方式中断Promise
// throw「我是中断的原因’)
return Promise.reject ('我是中断的原因’)
}). then(function(res){
console.log(res)
}).then(function(res){
console.log(res)
</script>

3.宏任务和微任务

宏任务: 宏任务是JavaScript中最原始的异步任务,包括setTimeout、setInterVal、AJAX等,在代码执⾏环境中按照同步代 码的顺序,逐个进⼊⼯作线程挂起,再按照异步任务到达的时间节点,逐个进⼊异步任务队列,最终按照队列中的 顺序进⼊函数执⾏栈进⾏执⾏。

微任务: 微任务是随着ECMA标准升级提出的新的异步任务,微任务在异步任务队列的基础上增加了【微任务】的概念,每 ⼀个宏任务执⾏前,程序会先检测中是否有当次事件循环未执⾏的微任务,优先清空本次的微任务后,再执⾏下⼀ 个宏任务,每⼀个宏任务内部可注册当次任务的微任务队列,再下⼀个宏任务执⾏前运⾏,微任务也是按照进⼊队 列的顺序执⾏的。

总结:在JavaScript的运⾏环境中,代码的执⾏流程是这样的:

1. 默认的同步代码按照顺序从上到下,从左到右运⾏,运⾏过程中注册本次的微任务和后续的宏任务:

2. 执⾏本次同步代码中注册的微任务,并向任务队列注册微任务中包含的宏任务和微任务

3. 将下⼀个宏任务开始前的所有微任务执⾏完毕

4. 执⾏最先进⼊队列的宏任务,并注册当次的微任务和后续的宏任务,宏任务会按照当前任务队列的队尾继续向 下排列 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值