一、前言
今天查看了requireJs方面的知识,看着看着就看到了JS中同步与异步操作的知识点,经过查阅了很多的资料,基本了解了JS的同步与异步的操作,其中涉及到的知识点如下:
- 什么时同步和异步?
- JS的是基于事件驱动的单线程语言,为啥会有异步操作这种多线程的操作???
- 浏览器线程,浏览器内核线程间的合作?
- JS的异步操作都有哪些?它是如何工作的?
二、js单线程
- JS的单线程
单线程的含义是js只能在一个线程上运行,也就是说,同一时间只能做一件事情,其他的任务则会放在任务队列里面排队等等js线程处理。
但是值得注意的是,虽然js是单线程语言,但是并不代表浏览器内核中的js引擎线程只有一个。js引擎有多个线程,一个主线程,其他的线程配合主线程工作
三、为什么js选择单线程
与它的用途有关。作为浏览器脚本语言,Javascript主要用途是与用户互动,以及操作dom。这决定了它只能是单线程,否则会带来复杂的同步问题。比如,假设javascript同事有两个进程,一个线程在某个DOM阶段添加内容,另一个线程删除了这个节点,这是浏览器应该以哪一个线程为准?想要实现这个问题,肯定要加入线程锁这个概念,那就复杂多了。
单线程与异步确实不能同时成为一个语言的特性,JS选择成为单线程语言,所以它本身是不可能异步的,但是js的宿主环境(比如浏览器,Node)是多线程的,宿主通过某种方式,使得js具备异步的属性,如果你理解了,你会发现js的机制是多么的简单高效!
四、同步和异步
- 同步:一次只能完成一件任务,如果有多个任务,必须排队
- 异步:每一个任务有一个或者多个回调函数(callback),前一个任务执行后,把里面回调函数抛出来,给浏览器的另外一个线程处理。而后一个任务是不等待前一个任务结束就执行。
- 一个例子来说明异步和同步:
<html> <head> <title>异步与同步</title> </head> <body> <script> setTimeout(function () { console.log("异步任务") }) console.log("同步任务") </script> </body> </html> //输出: //同步任务 //异步任务 //执行顺序: //首先执行setTimeout,发现是个异步操作,就把这个异步操作丢给浏览器内核中的 //计时器线程,然后js主线程继续执行console.log("同步任务"),之后js主线程空闲, //从任务队列里面获取异步操作任务,放到js主线程栈中执行,输出“异步任务”
五、异步的好处
1.异步的好处
用一个同步与一个异步图进行说明,假设有四个任务(1、2、3、4),它们各自的执行时间都是10ms,其中,任务2是任务3的前置任务,任务2需要20ms的响应时间。
2.适合的场景
可以看出,当我们的程序需要大量I/O操作和用户请求时,js这个具备单线程,异步,事件驱动多种气质的语言是多么应景!相比于多线程语言,它不必耗费过多的系统开销,同时也不必把精力用于处理多线程管理,相比于同步执行的语言,宿主环境的异步和事件驱动机制又让它实现了非阻塞I/O,所以你应该知道它适合什么样的场景了吧!
五、JS的异步操作有哪些
- 定时器函数setTimeout(交给定时器线程处理)
- 事件绑定(onclick、onkeydown....,交给事件触发线程处理)
- AJAX(交给HTTP线程处理)
- 回调函数
我们已经知道,js一直是单线程执行的,浏览器为了几个明显的耗时任务(上面四点),单独开辟线程解决耗时问题。但是JS除了这几个明显耗时问题外,可能我们自己写的程序里面也会有耗时函数,怎么解决?我们肯定不能直接开辟单独的线程,但是我们可以利用浏览器给我们开发的窗口(定时器线程和事件触发线程)
六、任务队列
因为Javascript被设计为单线程,意味着一次只能执行一个任务,所有任务都需要排队