写在最前面
同步代码
(实际是阻塞了代码),一句话总结,async 函数就是 Generator 函数的语法糖,返回了一个 promise.resolve() 的结果。阮一峰老师的 async 教程不着急介绍 promise 的详情,首先我们从最开始的同步和异步讲起:
简单的理解
console.log('synchronous'); //我们能立即得到 synchronous
简单的理解
来看一个图
一个浏览器通常由以下几个常驻的线程:
渲染引擎
和js引擎线程
是不能同时进行的,渲染线程
在执行任务的时候,js引擎线程
会被挂起。因为若是在渲染页面的时候,js处理了DOM,浏览器就不知道该听谁的了渲染引擎
:Chrome/Safari/Opera用的是Webkit引擎,IE用的是Trdent引擎,FireFox用的是Gecko引擎。不同的引擎对同一个样式的实现不一致,就导致浏览器的兼容性问题。JS引擎:
js引擎可以说是js虚拟机,负责解析js代码的解析和执行。通常有以下步骤: JS引擎也是不同的
:Chrome用的是V8,FireFox用的是SpiderMonkey,Safari用的是JavaScriptCore,IE用的是Chakra。总结一点:JavaScript是单线程的,但是浏览器不是单线程的。一些I/O操作,定时器的计时和事件监听是由其他线程完成的。
开局一张图
导图要表达的内容用文字来表述的话: 1.同步和异步任务分别进入不同的执行"场所" 2.同步的进入主线程,异步的进入Event Table并注册回调函数到 Event Queue 中。 3.当主线程执行完毕以后,然后会去 Event Queue 查询,时候如果存在的函数,放进主线程中继续执行。 4.上述就是event loop的执行
说了这么多文字,不如直接一段代码更直白:
console.log('script start');
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function cb() {
console.log('promise2');
});
console.log('script end');
// script start
// promise1
// script end
// promise2
复制代码
分析这段代码:
首先执行,打印 script start
然后进入 promise 函数打印 promise1,执行 resolve()
在 then 执行的时候我们把异步回调放进了 event table 中注册相关的回调函数。
new promise 执行完毕,回调函数cb() 进入Event Queue。
执行 打印 script end;
主线程从Event Queue读取回调函数 cb 并执行。
微任务
的时候,优先执行 微任务
macro-task(宏任务):包括整体代码script,setTimeout,setInterval micro-task(微任务):Promise,process.nextTick
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
// 思考上述代码打印结果
复制代码
注意几个点
1、js是单线程的。
2、promise被定义后是立即执行的,但是他的resolve是异步的。
3、promise的异步优先级高于setTimeout。
4、async会返回一个promise对象,await关键字会让出线程。
- 定义异步函数 async1, 异步函数 async2
1. console.log('script start'); 执行 (1)`script start`
2. setTimeout 执行,异步放入异步队列中,注意这是一个宏任务(我们标记为 macro1)
3. 执行 async1(), 打印 (2)`async1 start`, 执行 async1() 中的 await async2(): 打印 (3)`async2`;
遇到 await 后面的函数进入任务队列,这里又注册一个微任务(我们标记为 mico1);到这里 async1() 就执行完了
4. 执行 new Promise:打印 (4)`promise1`,执行 resolve();
然后在 then 中注册回调函数,console.log('promise2') 函数进入任务队列;
注册 event queue(我们标记为 mico2).这里 new Promise 就执行完了。
5. 执行 console.log('script end');, 打印 (5) `script end`;
6. 上面