首先,由于JavaScript语言是单线程的*(目标为浏览器端,出生即为单线程)*,因此就须要异步,不然JavaScript脚本智能自上而下执行,若是在上部存在一些极其复杂的代码须要解析很长的时间的话,下面的代码就会遭到阻塞,也就是用户感觉到的卡死.javascript
因为是单线程语言,因此JavaScript实现异步的方法是经过**事件循环(event loop)**来实现异步.html
console.log('I’m first one code!');
setTimeout(() => {
console.log('I’m setTimeout function code!');
})
console.log('I’m last one code! ');
复制代码
这段代码的运行结果为java
I’m first one code!
I’m last one code!
I’m setTimeout function code!
复制代码
因此,代码并无是自上而下执行,setTimeout函数是延迟了一段时间,等其余语句执行完了采起执行,这种状况就为异步。es6
根据上一部分咱们知道,JavaScript把事件分为两类:同步与异步api
因此JavaScript的执行机制实际上是:promise
这个循环即为 event loop浏览器
咱们先看一段代码bash
setTimeout(() => {
console.log('1');
});
new Promise((resolve) => {
console.log('2');
}).then( () => {
console.log('3');
});
console.log('4');
复制代码
若是按照咱们刚才的理解,这段代码的结果应该为 2,4,1,3异步
But unfortunately!他的结果为 2,4,3,1async
这也引入了另外两个概念:宏任务与微任务
因此任务应该分为这两类:
因此js的执行机制实际上是
先执行一个宏任务,过程当中若是遇到微任务先把他放到微任务的事件队列中,当宏任务执行完毕后,再去查看微任务的事件队列,将微任务一次执行完,执行完毕后再去进行下一个队列的宏任务,以此循环.
借用一张图演示
刚忽然发现已经绕远了:car:,赶快漂移回原来的主题,async,一个在ES2017中提出的异步方案,有人说他是Generator函数的语法糖,只是把Generator函数的 * 替换为 async,把yield替换为await。咱们先不讨论这句话说得对不对:speak_no_evil:,但它确实是基于了Generator的一种改进,它让异步变得更简单了。
若是要简述的话,一旦你的函数前带上了async,你的函数返回值就一定是promise对象.(他就像真香定律同样是没有能够逃过的)就算你写的函数里返回的不是promise,他也会自动用Promise.resolve()包装起来让他成为一个promise对象。
因此,若是咱们简单理解async关键字的话,他其实就是给函数加上一个标识,说明这个函数内部有异步操做。
咱们再次简单的介绍如下 await,await 其实等的是右侧表达式的结果.
若是右侧是一个函数,则是这个函数的返回值。若是是一个值则就为此值.
咱们经过一个例子来"见识见识"它
async function fun1(){
console.log('fun1 is started!');
await fun2();
console.log('fun1 ending!');
}
async function fun2(){
console.log('fun2 is running!');
}
fun1();
console.log('script start');
复制代码
咱们知道,await是经过执行到此时让出线程,经过阻塞后面的代码来执行,但咱们执行上面的代码发现结果为
fun1 is started!
fun2 is running!
script start
fun1 endding!
复制代码
注意,这里fun2先于"script start" 执行,因此 await 的那个表达式的执行顺序实际上是从右到左,即为执行了fun2后读到了await关键字,而后阻塞后面的代码,这点很是重要,由于以前由于"一旦遇到await就立马退出线程,阻塞后面的代码"的观点,认为 await也会阻塞他后面的那个表达式,但其实否则。
await 与 async 的关系就像鱼和水, await必需要有async才能够存在,而async却不必定须要有await。
通常来讲 await等到的右侧表达式结果有两种状况:
Promise or Not Promise。
我的Github:Reaper622
欢迎学习交流