Kalec的网络日志

漂浮的灵魂

HOME 首页 js的运行机制

js的运行机制

基础总结
2018-03-11 16:18:00

js的运行机制

js的无数小坑坑

渐渐js用得慢慢多了些的时候,会发现这门语言有太多奇怪的东西,而这些东西总会引起一些好奇。特别我那个时候刚刚开始学习的时候,因为是第一次接触动态弱类型的语言,就感觉这鬼玩意好不严谨啊!特别还有这种操作…变量可以后声明,还不报错,这什么鬼!

console.log(a); //undefined var a = 5;

那个时候还有这种

var a = 34; setTimeout(function(){ // balabala },1000) console.log(a); //执行直接出现34,并没有等待1s

总觉得设定延时后,后面的内容会等待延时后执行(ps:忘了当时做的是什么了,貌似是个轮播图,这个就随意模拟一下当时的情况吧😰)
其实,众所周知等待了1s以后,当然只是执行了里面的回调函数,然而后面的打印a的确是在1s前面执行了…
还有就是上一篇js闭包(上)中提到的那个

for (var i = 1; i <= 5; i++) { setTimeout(function timer() { console.log(i); }, i * 1000) console.info(i); }

为了更加直观,这次咱在定时器外,循环内加一个打印i,运行后,瞬间打印出了1,2,3,4,5然后每隔一秒打印一个6打印5次。足以说明定时器是在循环外执行的!
我们在此可以看出,需要消耗时间的事件等待,io读写等耗时的任务,都会自动被移到程序最后执行。这就引发了好奇心,就想知道这是怎样的一个运行方式。
大家伙都明白,JavaScript是一门单线程语言。(虽然说用某些api等可以实现多线程,但单线程是它的本质)
传统的单线程会引发一些灾难性的问题,若是等待一个事件等消耗大量时间的内容,后面的内容会被阻塞,若是出现问题,后面的内容将永远不能得到执行权。
为了保证效率,js这门语言把执行任务在内核上就分为了,同步任务与异步任务。

执行机制

引用自阮一峰老师
同步任务在主线程上执行时候创建一个执行栈。
主线程之外,存在一个“任务队列”,只要异步任务有了结果,便在队列中放置一个事件。
一旦执行栈中的所有同步任务完成后,系统读取任务队列,查看里面的事件,那些异步任务结束等待,进入执行栈开始执行。
主线程不断重复上面三步。

异步任务就是消耗大量时间的io读写,以及事件等待,也就是说js的运行机制便是,先把能够快速执行的同步任务搞定并且读取消耗大量时间的任务,让其进入等待…待同步任务完成后,继续执行前面暂停的异步任务,主线程执行其异步任务,也就是执行其对应的回调函数。
也正是这种机制,高效的非阻塞io,让js在对抗io高并发场景体现出了足够的优势。

常用的异步

前面所提到的异步任务常用的大致有这些,发送或者接受网络请求req.send(),定时器setTimeout()setInterval()
node中就更多了有磁盘读写,数据库读写,process.nextTick()setImmediate()等…

示例

用这个来理解上次的运行机制我觉得OK!
其实,不用看程序,只看结果就能看出其实挺有意思的,和你平时能否合理利用时间差不多,毕竟人也不能一心二用,类似单线程。

用async和await模拟同步

const doSomeThing = (sth, time) => { console.log(sth,`耗时 ${time} ms`); return new Promise(resovle => { setTimeout(resovle, time) }) } const Kalec = { doSomeThing }; const Karri = { doSomeThing }; ;(async () => { console.log('Karri来到门口想洗澡'); await Kalec.doSomeThing('我在蹲坑',3000); await Karri.doSomeThing('Karri洗澡',3000); console.log('Karri去做别的事情了'); })()

运行结果如下

Karri来到门口想洗澡
我在蹲坑 耗时3000ms
Karri等待时间过长有点生气,Karri洗澡 耗时3000ms
Karri去做别的事情了

异步为这样

const doSomeThing = (sth, time) => { setTimeout(() => { console.log(sth+'done!'); }, time); } const Kalec = { doSomeThing }; const Karri = { doSomeThing }; ;(() => { console.log('Karri来到门口想洗澡,发现我在蹲坑'); Kalec.doSomeThing('蹲坑',3000); Karri.doSomeThing('Karri洗澡',3000); console.log('Karri去做别的事情了'); })()

运行结果为

Karri来到门口想洗澡,发现我在蹲坑
Karri去做别的事情了
蹲坑done!
Karri洗澡done!

留言

  • 皮皮虾
    说:
    1

    来踩一脚,嘿嘿😁

    2018-03-15 00:12:42
    |

评论

看不清?换一个