单线程,同步异步,阻塞非阻塞的理解
一.概念理解
1.同步异步:
同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)所谓同步,就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由*调用者*主动等待这个*调用*的结果。
而异步则是相反,*调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在*调用*发出后,*被调用者*通过状态、通知来通知调用者,或通过回调函数处理这个调用。
2.阻塞非阻塞:
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
作者:严肃
链接:https://www.zhihu.com/question/19732473/answer/20851256
来源:知乎
3.单线程:
我们常说“JavaScript是单线程的”。
所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。不妨叫它主线程。
但是实际上还存在其他的线程。例如:处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程(例如在Node.js中)等等。这些线程可能存在于JS引擎之内,也可能存在于JS引擎之外,在此我们不做区分。不妨叫它们工作线程。
二.JS中的同步异步理解:
1.同步:
Math.sqrt(2); console.log('Hi'); 第一个函数返回时,就拿到了预期的返回值:2的平方根。 第二个函数返回时,就看到了预期的效果:在控制台打印了一个字符串
2异步:(以异步函数setTimeout为例)
setTimeout(function(){console.log("a")}, 500); console.log("b"); //"b" //"a"
setTimeout函数返回时,并不能立即得到结果,而是先运行后面的程序,等到被调用函数通知时(500ms以后通知),再运行。
3.异步过程的构成要素:
主线程发起一个异步请求,相应的工作线程接收请求并告知主线程已收到(异步函数返回);主线程可以继续执行后面的代码,同时工作线程执行异步任务;工作线程完成工作后,通知主线程;主线程收到通知后,执行一定的动作(调用回调函数)。
所以,从主线程的角度看,一个异步过程包括下面两个要素:
-
发起函数(或叫注册函数)
- 回调函数
callbackFn
4.消息队列与事件循环:
工作线程将消息放到消息队列,主线程通过事件循环过程去取消息。消息就是注册异步任务时添加的回调函数。
-
消息队列:消息队列是一个先进先出的队列,它里面存放着各种消息。
-
事件循环:事件循环是指主线程重复从消息队列中取消息、执行的过程。
作者:manxisuo
链接:https://segmentfault.com/a/1190000004322358
三.JS中异步编程的几种方式
1.回调函数:
假设有函数
f1();
f2();
f2必须在f1完成后运行,f1又是一个耗时的应用
则可使用异步调用:
function f1(f2){
setTimeout(function () {
console.log("a")
// f1的任务代码
f2()}, 1000)}
function f2(){console.log("b")};
f1(f2);
console.log("c");}
//"c"
//"a"
//"b"
这样,就把同步操作变成了异步操作;
2.事件监听:采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
还是以f1和f2为例。首先,为f1绑定一个事件(这里采用的jQuery的写法)。 f1.on('done', f2); 上面这行代码的意思是,当f1发生done事件,就执行f2。然后,对f1进行改写: function f1(){ setTimeout(function () { // f1的任务代码 f1.trigger('done'); }, 1000); } f1.trigger('done')表示,执行完成后,立即触发done事件,从而开始执行f2。
3.发布、订阅:
4.Promise对象:
Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。比如,f1的回调函数f2,可以写成: