一、同步异步编程
(一)浏览器是多线程的
1. GUI渲染线程 2. HTTP网络请求线程(并发数6~7) 3. 事件监听、定时器监听\...
(二)JS代码的运行是单线程的
浏览器只分配一个GUI渲染线程去执行我们的JS代码
- 对于大部分JS代码来讲上面代码没有执行完,下面代码是不能执行的 “同步编程”
- 但是对于某些JS代码来讲(事件绑定、定时器、Promise/async/await、Ajax等),我们需要在上面代码没有处理的情况下,GUI渲染线程能够继续向下执行 “异步编程”
console.log(1); console.time('AAA'); for (let i = 0; i < 99999999; i++) { if (i === 99999998) { console.log(2); } } console.timeEnd('AAA'); // => time/timeEnd可以记录一段程序执行的时间(时间受电脑性能和执行时候的环境转态影响) "事后统计法" 300MS~400MS console.log(3);
// 1 3 5 6 7 4 2 console.log(1); setTimeout(() => { console.log(2); }, 1000); console.log(3); setTimeout(() => { console.log(4); }, 0); // => 并不是立即执行, 需要等待浏览器的最小反应时间 5~6MS console.log(5); // console.time('A') // 145ms左右 for (let i = 0; i < 99999999; i++) { if (i === 99999998) { console.log(6); } } // console.timeEnd('A') console.log(7);
// 2 4 5 7 9 3 1 6 8 错误 // 2 4 5 7 9 6 3 8 1 // 前面两个定时器都是循环结束前,放到任务队列中的;后面两个定时器都是循环结束后,放到任务队列中的。 // for循环结束后,前面2个定时器已经到了执行时间了,GUI渲染线程结束后,会先执行这两个定时器。 setTimeout(() => { console.log(1); }, 20); console.log(2); setTimeout(() => { console.log(3); }, 10); console.log(4); for (let i = 0; i < 90000000; i++) { // do soming 79MS } console.log(5); setTimeout(() => { console.log(6); }, 8); console.log(7); setTimeout(() => { console.log(8); }, 15); console.log(9);
for (var i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }, 0); } // 第一次循环 向任务队列中插入一个定时器 // 第二次循环 向任务队列中插入一个定时器 // ... // 第五次循环 向任务队列中插入一个定时器 // 循环结束 全局下的i=5 任务队列中有5个定时器 【GUI空闲】 // 定时器执行中遇到i 不是自己的,则找全局的,全局的i=5 // => 5 * 5
setTimeout(() => { console.log(1); while (1 === 1) { } }, 10); console.log(2); for (let i = 0; i < 90000000; i++) { // do soming 79MS } // 循环结束 任务1已经到时间了 console.log(3); setTimeout(() => { console.log(4); }, 5); console.log(5);
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'); // ------------------------ /* * 任务队列: * 微任务 * 任务2:resolve(result)控制then存放的方法执行 * 宏任务 * 任务1:AJAX请求 * * GUI空闲 * 任务1数据请求回来,触发success回调函数,执行resolve(result) 【设置了一个微任务】 * GUI空闲 * 执行任务2 */ new Promise(resolve => { $.ajax({ url: 'xxx', success: result => { resolve(result); } }); }).then(result => { });
function func1() { console.log('func1 start'); return new Promise(resolve => { resolve('OK'); }); } function func2() { console.log('func2 start'); return new Promise(resolve => { setTimeout(() => { resolve('OK'); }, 10); }); } console.log(1); setTimeout(async () => { console.log(2); await func1(); console.log(3); }, 20); // 循环大约要进行80MS左右 for (let i = 0; i < 90000000; i++) { } console.log(4); func1().then(result => { console.log(5); }); func2().then(result => { console.log(6); }); setTimeout(() => { console.log(7); }, 0); console.log(8);