同步与异步
由于js是用来控制DOM的,所以js必须是单线程的,因为如果多个线程同时控制DOM操作,那么页面必然就乱套了。为了避免复杂性,所以它是单线程的。
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。
虽然js单线程的,但是浏览器内部不是单线程的,以此js才实现了异步。一些I/O操作、定时器的计时和事件监听(click, keydown…)等都是由浏览器提供的其他线程来完成的。
单线程的js执行任务的时候必须一个个来,任务过多就需要排队了,但是如果某个任务需要时间过长,一直等下去也不是个事,那么就有了 任务队列 ,js将任务划分为同步任务和异步任务,同步任务是在主进程中,等前一个任务执行完毕,再执行的任务,如:立即执行、不耗时的任务,如变量和函数的初始化、事件的绑定等等那些不需要回调函数的操作。异步任务即,不会直接在主进程中执行,而是先进入任务队列,等待主进程中任务执行完毕再执行,如用户的点击事件、浏览器收到服务的响应和setTimeout插入的事件。
异步运行的过程如下:
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步
Callback:即回调函数,异步任务须指定回调函数,执行栈开始执行异步任务即执行异步任务中的回调函数。
Promise:
假设有多个需要串行执行的异步操作,容易产生回调地狱,并且错误处理也很复杂,所以有了Promise。
Promise就是能把原来的回调写法分离出来,可以在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作,即在异步操作执行完后,用链式调用的方式执行回调函数。
Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。其核心思想一个Promise代表一个异步操作的结果,本质上是一个状态机,拥有三种状态:
pending 待定,一个Promise最初的状态。
fulfuilled 已实现 一个成功操作的Promise的状态
rejected 已拒绝 一个失败操作的Promise的状态
如图所示,pending状态可以直接变为fulfilled或者rejected的状态,也可以通过resolve方法实现状态的变化。