js代码的执行流程是前端工程师必须熟悉的,要理解js代码的运行流程,要理解这么几个概念,主线程,任务队列,事件循环,要分清setTimeout,setInterval,setImmidiate,process.nextTick这几个api的区别。
js是单线程的,设计单线程的原因是因为防止多个线程同时操作dom,引起冲突,就像安卓里只有在主线程可以更新ui一样,h5新加了web worker api,但是这些线程是不能操作dom的,原因也是一样。单线程,所有的代码会在主线程中依次同步的执行,但是有一些耗时的操作,比如一个http请求,发出请求去,不可能一直让ui阻塞的等待数据返回,当然同步的跳转地址和提交表单是这样的,为了提升用户体验,js把这些操作异步化了,设计了一个任务队列,当一个异步任务执行后,进入阻塞状态,主线程会继续往下执行别的代码,当异步任务执行完成,会往任务队列中放置一个事件,当主线程执行完代码后,会去取任务队列中的事件中的回调函数来执行,当这些回调函数都执行完以后,再去任务队列中取,这样访问一次任务队列,把其中的事件都取出来,执行对应的回调函数的过程叫做一次事件循环,js就是这样利用任务队列和事件循环实现了异步的执行流程。
事件监听,ajax请求,定时器都是异步的操作,对应的回调函数都会在任务完成后封装成事件放入任务队列等待被执行。其中,定时器有几个api,setTimeout,setInterval,以及node中添加的setImmidiate和process.nextTick,都可以把一个函数变成一个异步的任务,会在一段时间后封装成事件放入任务队列中。但是它们又有区别,setTimeout是一段时间后把回调函数封装成事件放入执行队列,setInterval是每隔一段时间,setImmidiate这个api相当于setTimeout(fn,0),是立即把回调函数封装成事件push到任务队列中,process.nextTick略有不同,他是在主线程执行完,执行任务队列中的任务之前执行的,不管有多个nextTick都会执行,所以不能在递归中用,不然任务队列中的代码将永远得不到执行的机会。如果想实现异步的递归,用setImmidiate或者setTimeout。
js的运行流程,主要分同步和异步,异步要理解任务队列和事件循环,理解它为什么这么设计。理解了js代码的执行顺序,也就是理解了js的运行时,能够帮我们跟深入的理解js代码,写出更优雅的代码,以及解决一些常见的bug。