JS基础——同步异步的区别

40次阅读

共计 2134 个字符,预计需要花费 6 分钟才能阅读完成。

javascript 语言是一门“单线程”的语言,不像 java 语言,类继承 Thread 再来个 thread.start 就可以开辟一个线程。所以,javascript 就像一条流水线,仅仅是一条流水线而已,要么加工,要么包装,不能同时进行多个任务和流程。
“同步”——一下就让人想到“一起”这个词;

“异步”呢,从字面来讲,好像是在不同的(异)的 ways 上 do something,那首先想到的词可能是“一边 … 一边 …”, 比如‘小明一边吃雪糕一边写作业’,这完全没毛病,雪糕吃完了,作业也写完了,这就是异步?那就大错特错了!

其实同步和异步,无论如何,做事情的时候都是只有一条流水线(单线程),同步和异步的差别就在于这条流水线上各个流程的执行顺序不同。
最基础的异步是 setTimeout 和 setInterval 函数,很常见,但是很少人有人知道其实这就是异步,因为它们可以控制 js 的执行顺序。我们也可以简单地理解为:可以改变程序正常执行顺序的操作就可以看成是异步操作。如下代码:
console.log(“1”);
setTimeout(function() {
console.log(“2”)
}, 0 );
setTimeout(function() {
console.log(“3”)
}, 0 );
setTimeout(function() {
console.log(“4”)
}, 0 );
console.log(“5”);
输出顺序是什么呢?

可见,尽管我们设置了 setTimeout(function,time)中的等待时间为 0,结果其中的 function 还是后执行。
尽管 setTimeout 的 time 延迟时间为 0,其中的 function 也会被放入一个队列中,等待下一个机会执行,当前的代码(指不需要加入队列中的程序)必须在该队列的程序完成之前完成,因此结果可能不与预期结果相同。
这里说到了一个“队列”(即任务队列),该队列放的是什么呢,放的就是 setTimeout 中的 function,这些 function 依次加入该队列,即该队列中所有 function 中的程序将会在该队列以外的所有代码执行完毕之后再以此执行,这是为什么呢?因为在执行程序的时候,浏览器会默认 setTimeout 以及 ajax 请求这一类的方法都是耗时程序(尽管可能不耗时),将其加入一个队列中,该队列是一个存储耗时程序的队列,在所有不耗时程序执行过后,再来依次执行该队列中的程序。
又回到了最初的起点——javascript 是单线程。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
于是就有一个概念——任务队列。如果排队是因为计算量大,CPU 忙不过来,倒也算了,但是很多时候 CPU 是闲着的,因为 IO 设备(输入输出设备)很慢(比如 Ajax 操作从网络读取数据),不得不等着结果出来,再往下执行。于是 JavaScript 语言的设计者意识到,这时主线程完全可以不管 IO 设备,挂起处于等待中的任务,先运行排在后面的任务。等到 IO 设备返回了结果,再回过头,把挂起的任务继续执行下去。
于是,所有任务可以分成两种,
一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入 ” 任务队列 ”(task queue)的任务,只有等主线程任务执行完毕,” 任务队列 ” 开始通知主线程,请求执行任务,该任务才会进入主线程执行。
具体来说,异步运行机制如下:

所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
主线程之外,还存在一个 ” 任务队列 ”(task queue)。只要异步任务有了运行结果,就在 ” 任务队列 ” 之中放置一个事件。
一旦 ” 执行栈 ” 中的所有同步任务执行完毕,系统就会读取 ” 任务队列 ”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
主线程不断重复上面的第三步。

只要主线程空了,就会去读取 ” 任务队列 ”,这就是 JavaScript 的运行机制。这个过程会不断重复。
“ 任务队列 ” 中的事件,除了 IO 设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等),比如 $(selectot).click(function),这些都是相对耗时的操作。只要指定过这些事件的回调函数,这些事件发生时就会进入 ” 任务队列 ”,等待主线程读取。
所谓 ” 回调函数 ”(callback),就是那些会被主线程挂起来的代码,前面说的点击事件 $(selectot).click(function) 中的 function 就是一个回调函数。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。例如 ajax 的 success,complete,error 也都指定了各自的回调函数,这些函数就会加入“任务队列”中,等待执行。
作者:YinghaoGuo 来源:CSDN 原文:https://blog.csdn.net/qq_2285… 版权声明:本文为博主原创文章,转载请附上博文链接!

正文完
 0