当前位置 博文首页 > 文章内容

    JS(JavaScript)的本质

    作者:1663631723 栏目:最新时讯 时间:2020-04-28 9:25:33

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



         我是张大胖,这是我第一天上班,说实话我有点紧张。 

         想想在校4年,除了熬夜打游戏之外,我学得实在是不怎么样。 

         不过我遇上了好时候,计算机行业正处于飞速发展期,毕业后我顺利找了一份工作,老板叫Netscape,没错,就是那个古老的浏览器。 

         首次见面,Netscape给我分配了工位,告诉我:“你的任务就是执行JavaScript代码,每次遇到函数调用,就把函数压入你桌子上的栈中。” 

         栈?这我听说过,大学的数据结构课讲过,一个先进后出的数据结构, 教材上说用栈可以计算四则运算。奥,对了,还可以对一个二叉树做非递归的中序遍历,至于还有什么用处,老师们也没说,我就不知道了。 

         为了让我上手,Netscape给了我一段代码:

    function mul(x,y) {

    console.log("x="+x +",y="+y)

    return x*y

    }

    function square(x) {

    return mul(x , x)

    } 

    square(7)

         代码非常简单,就是两个简单的函数调用。 

         我小心地接过来,开始运行。 

         按照Netscape老板的指示,我给这段代码弄了一个虚构的“包裹”函数"main" ,先压入栈中。

         main函数要调用square,于是square函数也被压入栈。square调用mul, mul调用console.log  ,于是栈就变成了这个样子:

    e9b30675c74059e61cf9931d9088b77b.png

         执行完函数,再把他们从栈中一一弹出,直到栈变空为止。 

         很简单嘛!原来大学里学的栈操作还有这么一个用途啊:执行函数调用。 

    唯一的员工:单线程

         过了试用期,我正式开始上岗,每天的工作都是老一套,Netscape老板从网上下载HTML, JavaScript, CSS等文件,然后把JavaScript交给我来执行。 

         时间久了,我就觉得很奇怪,公司似乎只有我一个打工的,Netscape老板立的规矩很奇葩:所有的JavaScript代码,不管有多长、多复杂,都由我一个人一行一行地执行。 

         难道他不想多招几个人同时并行执行吗,那样就快多了!

         他对外宣传起来是一套一套的:JavaScript是一门非常简单的语言, 一定要单线程执行,这样程序员就不用考虑多线程的同步、通信、加锁等问题了。 

         听起来很有道理,可是我知道这主要是由于他抠门,不愿意花钱雇更多的员工。 

         看看CPU阿甘是8核的, 单线程的话只有一个核心可以使用,经常出现一核有难,多核围观的情况。 

         可是喜欢JavaScript的人越来越多,Netscape老板发了财,非常得意,喝醉了就经常吹牛:我这套单线程执行的体系完美无缺,用一个栈搞定一切函数调用!

    异步函数怎么办?

         直到有一天,我遇到这么一段代码:

    function hello(){

     console.log("hello after 5 seconds");

    }

    setTimeout(hello, 5000)

    console.log("done")

         我第一次遇到了setTimeout这个函数,不知道该怎么处理,老板说这是他的函数,于是我也把它压栈,然后请他去执行。 

    08dbe3ef7cf3d9e300166642e43baecc.png

         执行完setTimeout,再去执行log函数:

    91d82706d95f6a87e103c61b36608d0a.png

         log函数执行完了,弹出。 

         main函数也执行完了,弹出。 

         栈空了!

    a1a232f643d6086d63f920fe91e6f9dc.png

         我觉得有点懵! 

         这个setTimeout(hello, 5000)的意思不是说等待5秒以后执行hello函数吗? 

         现在栈空了,hello函数没有执行的机会了, hello 函数丢了?! 

         Netscape老板酒醒了:“不对啊,你应该把hello函数压入栈中执行啊。” 

         我说:“setTimeout是你执行的,只有你才知道5秒钟后把hello函数压入栈中啊!” 

         老板拍了一下脑门:“奥,对,原来你都是同步执行代码的,现在要变成异步了,让我想想怎么处理吧。”

    队列

         第二天, 老板又招来一个新人:小李。 

         小李的工位就在我的旁边,桌子有一个队列, 这是另外一个重要的、先进先出的数据结构。 

    e9b30675c74059e61cf9931d9088b77b.png

         可是他的队列又有什么用呢? 

         老板说:小李,我交给你一个重要任务,你要时刻监视旁边张大胖的栈,如果栈空了,就把你队列中的事件拿出来,把事件关联的函数压入栈中,让张大胖去执行。 

         小李立刻问道:“可是谁往我的队列中加入‘事件’啊!”

         老板说:“那自然是我了!来,我们再来执行下这段代码。”

    function hello(){

        console.log("hello after 5 seconds");

    }

    setTimeout(hello, 5000) 

    console.log("done")

         我又开始了一轮把main,setTimeout,log压栈/出栈的操作。 

         不一会儿,我面前的栈就空了。 

         我幸灾乐祸地看着老板,他设置了一个定时器,5秒的时间到了,他把一个和hello函数关联的事件放入了小李的队列中。 

         小李不敢怠慢,看到我这里栈空了, 立刻从队列中取出事件,把关联的hello函数放入我的栈中。 

         既然栈中有了函数,我不得不执行。 

         终于,hello函数被执行了, "hello after 5 seconds”被正确输出了。

    事件队列

         我觉得老板的这个做法很是古怪,那个定时器到时间以后,直接把hello函数压入我的栈不就行了?!还非得经过小李中转一下,纯属脱裤子放屁,多此一举。 

         老板似乎看透了我的心思,淡淡一笑:你有所不知,我们软件世界讲究职责分离,我这边只是产生事件, 加入小李的队列。

         小李承担的职责就是“事件循环”,他监测队列中的事件,然后把相关需要执行的函数(hello函数)加入到你的栈中, 你负责的就是执行了。我们三个人完美配合,共同完成工作。

         我还是不解:“为了一个简单的timeout,有必要搞这么复杂的公司组织架构吗?”

         “很有必要,将来我还会成立一个Web API的部门,不仅用来处理定时器(Timer)事件,还要实现XMLHttpRequest 的事件,DOM的事件等等,你们知道这些事件之间有什么相同之处吗?”

         小李比较机灵:“难道是都支持异步处理,基于事件的编程?”

         “没错,张大胖以单线程的方式一步步地执行JavaScript代码,遇到那些耗时的操作,必须通过注册一个回调函数的方式来异步处理,具体的实现办法,就是事件队列和事件循环了 !”

         老板吩咐小李把他的想法画成一幅组织架构图,贴到了墙上,新加入的员工,只要能理解这幅图,基本上就可以上手干活了!

    fb46b0ee3d1d0e85de5fbc53fae0c083.png





    ————————————————

    文章来源:CSDN博客

    原文链接:https://blog.csdn.net/coderising/article/details/104284386

    如有侵权,请联系删除