刚接触js的时候,对于es6的promise、async、await简直怕的要死,甚至有段时间很是惧怕promise这个词,随着后面慢慢的接触,以为这个东西并不是那么难理解,主要仍是须要弄懂js的一些基础知识。那么接下来,跟上个人思路,一块儿完全弄懂promise、async、await。前端
若是要弄懂promise,就必须弄懂什么是异步、什么是同步,这篇文章主要是讲一下什么是同步、什么是异步。node
任何新语言的出现确定是与他当时的需求有关系的,js全称是Javascript,诞生于1995年(跟我同岁)。
最初他的诞生就是为了表单提交的时候作提示用的,在js问世以前,全部的表单都必须提交到服务端才能校验必填项,
好比你想申请一个qq号,各类信息填了一大堆,提交完才知道,你手机号少输入了一位从新输入,
那确定砸电脑的心都有了,这个时候,js出生了,由于是跟用户作实时交互的,因此最先叫livescript,
当时为了蹭蹭Java的热度,上户口的时候就改为了Javascript,一不当心长大了能够跟Java分庭抗礼了。
复制代码
js从诞生之初就是单线程,那为何是单线程呢?
为了让咱们这些菜鸡更容易入门?固然不是。
js主要的用途就是操做DOM,以及与用户的交互,这就决定了他只能是单线程,
好比你这个线程建立了一个DOM,那个线程给删除了,这时候浏览器应该以哪一个为准,
因此这个应该永远不会变,你前端发展的能造火箭了,js确定也是单线程的。
复制代码
你能够理解为同一个时间,你只能干一件事。今天下班早,你想给女友打个电话,女友可能跟其余小伙伴一块儿吃饭呢,
因为手机静音,因此听不到,你就一直打,一直打,啥都没干,把时间都浪费了,这就叫同步。由于js是单线程的嘛,因此js从小就是同步的。
来一段代码:
function second() {
console.log('second')
}
function first(){
console.log('first')
second()
console.log('Last')
}
first()
这个很简单,执行打印结果:
first、second、last
复制代码
那么js执行这段代码,到底发生了什么呢?这里面又有一个‘调用栈’的概念es6
是否是一听到什么堆栈就惧怕,别慌,没那么复杂,你能够理解为一个厕所,你们去上厕所,可是!不是先进先出,而是后进先出。用调用栈的概念,解释一下上面代码的执行顺序:promise
当执行此代码时,将建立一个全局执行上下文并将其推到调用堆栈的顶部;// 这个不过重要,下面是重点
first()函数先上,如今他在顶部;
而后打印‘first’,而后执行完了,这个时候这个console.log会自动弹走,就是这个console.log虽然是后进来的,可是他先走了;
如今first函数仍然在顶部,他下面还有second函数,因此不会弹走;
执行second()函数,这时候second函数在顶部;
打印‘second’,而后执行完了,弹走这个console.log,这时候second在顶部;
这个时候second函数的事儿都干完了,他也弹走了,这时候first函数在顶部;
浏览器会问,first你还有事吗,first说我还有一个,执行打印‘last’
复制代码
电话没打通,你就给女友发了个短信,洗澡去了,你回家了告诉我,(等我洗完了)再打给你,这就是异步。
后来为了提升效率,把浏览器的多个内核都用起来,HTML5提出Web Worker标准,
容许JavaScript脚本建立多个线程,可是子线程彻底受主线程控制,且不得操做DOM。
因此这并无影响js单线程的本质,js仍是每次只能干一件事,只不过把洗澡提早了而已。
来段代码:
const getList = () => {
setTimeout(() => {
console.log('我执行了!');
}, 2000);
};
console.log('Hello World');
getList();
console.log('哈哈哈');
执行顺序是:
Hello World、哈哈哈、我执行了!(两秒之后执行最后一个)
复制代码
这段代码执行,又发生了什么呢?这个地方又有一个‘消息队列’的概念,不慌!浏览器
刚才咱们说了,同步的时候,浏览器会维护一个‘执行栈’,除了执行栈,在开启多线程的时候,浏览器还会维护一个消息列表,除了主线程,其他的都是副线程,这些副线程合起来就叫消息列表。 咱们用消息列表的概念分析一下上面的代码:微信
按照执行顺序console.log('Hello World')先执行,浏览器一看,中央军(主线程)!你先过;
而后是getlist函数执行,浏览器看到setTimeout,你是八L(副线程)!你先靠边等着;
而后是console.log('哈哈哈')执行,中央军(主线程)!你也过;
而后浏览器问,还有中央军吗?没了,八L开始过!
复制代码
setTimeout(function() {
console.log('我是定时器!');
})
new Promise(function(resolve) {
console.log('我是promise!');
resolve();
}).then(function() {
console.log('我是then!');
})
console.log('我是主线程!');
执行顺序:
我是promise!
我是主线程!
我是then!
我是定时器!
复制代码
为何promise.then比定时器先执行呢?这个里面又涉及了一个‘事件轮询’的概念。多线程
上面咱们说了,浏览器为了提高效率,为js开启了一个不太同样的多线程,由于js不能同时执行嘛,那副线程(注意是副线程里面哈)里面谁执行,这个选择的过程,就能够理解为事件轮询。咱们先用事件轮询的顺序分析一下上面的代码,再来上概念:异步
promise函数确定首先执行,他是主线程嘛,打印‘我是promise’;
而后继续走主线程,打印‘我是主线程’;
而后主线程走完了,开始走消息列表;
(宏任务和微任务一会再讲)
这个时候会先执行promise.then,由于他是微任务,里面的‘我是then!’
消息列表里面在上面的是定时器,可是定时器是宏任务,优先级比较低,因此会日后排;
复制代码
**宏任务(Macrotasks):**js同步执行的代码块,setTimeout、setInterval、XMLHttprequest、setImmediate、I/O、UI rendering等。
**微任务(Microtasks):**promise、process.nextTick(node环境)、Object.observe, MutationObserver等。
微任务比宏任务要牛逼一点
浏览器执行的顺序:
(1)执行主代码块,这个主代码块也是宏任务
(2)若遇到Promise,把then以后的内容放进微任务队列
(3)遇到setTimeout,把他放到宏任务里面
(4)一次宏任务执行完成,检查微任务队列有无任务
(5)有的话执行全部微任务
(6)执行完毕后,开始下一次宏任务。
复制代码
可能写了那么多尚未涉及到promise和async、await,可是前面的同步、异步是基础,只有搞懂了同步异步究竟是怎么回事,才能有基础去学promise,下一章就来聊聊怎么让同步变异步,异步变同步,哪些地方用到!async
在这儿感谢掘金大神的文章,为了表示尊重,挂上地址!函数