一篇掌握最权威的JS同步异步编程原理

871 阅读4分钟

客套话

文章涉及的内容可能不全面,但量很多,需要慢慢看。我花了很长的时间整理,用心分享心得,希望对大家有所帮助。但是难免会有打字的错误或理解的错误点,希望发现的可以邮箱告诉我ghui_master@163.com,我会及时的进行修改,只希望对你有所帮助,谢谢。

重要性

接下来呢,我们把原生js里有一个非常重要的点 JS同步异步编程 来详细的看一下 , JS同步异步编程 不仅在面试中经常被问到,而且也是我们在真实的项目开发中,我们能不能有效的管控我们的数据请求,管控我们的异步操作,以及在项目当中我们很多的业务逻辑中,我们都得大量的应用同步异步编程的处理,那么此时需要我们把同步异步编程能够精准的,进准到骨子里的去掌握下来

JS 中的同步和异步编程

JS运行在浏览器中(浏览器只分配一个线程来运行JS =>JS是单线程的)
JS单线程导致大部分任务都是同步任务,只有及个别的事情属于异步的,如下:

  • 事件绑定
  • 定时器
  • AJAX(AXIOS) / FETCH(天生就是异步的)
  • Promise中的同步异步

Promise中的同步异步

  1. new Promise的时候,传递的exector函数一定是立即执行的,它属于同步的
  2. 基于then 或者 catch 存放的方法执行是异步的
new Promise((resolve, reject) => {
        console.1og(1);
        resolve(); //=>  resolve()执行才会进入.then 
}). then(() => {
        console .1og(2);
});
console.1og(3);

<!--输出
    1
    3
    2
    分析:
    当new Promise的时候 (resolve, reject) => {
        console.1og(1);
        resolve(); //=>  resolve()执行才会进入.then 
} 
1.exector函数是立即执行的
2.当执行完exector后,虽然是执行了resolve(); 但是不会立马把.then 中的方法立即执行,而是new Promise的 exector执行完之后,先执行then,通过 then 把 它里面写的这个方法函数 () => {
        console .1og(2);  
} 存起来 ,什么时候这些函数该执行呢
3.等到主线程的 console.1og(3); 执行完以后,主线程的任务都结束了,才会去把 resolve();这个执行控制  () => {
        console .1og(2);  
} 它执行;
-->
  1. async / await 也是异步的,尤其是await
await 是同步还是异步? 
    异步,虽然把它理解为等待同步状态,但他一定是异步的
async function fn( ) {
    await 10;
    console.1og(1);
}    
fn();
console.1og(2);
<!--输出
    2
    1
    分析:
    如果是同步的,我们先执行的fn();
    然后进入先等 await 10; 他没有出来之前,后面的不会执行,
    如果是同步的 包括 console.1og(2); 也不会执行 ,
    但是进入fu 后它里面的没有执行就执行  console.1og(2);先输出了
    说明 await一定是异步的
-->
  1. generator 函数
<!--
    在 generator 中执行一个方法,它面的代码不会执行,
    当我们只有通过 gt.next();后,代码才会一步一步执行,也可以理解为异步,
    asyncawait 就是基于generator构建出来的
    ----------------------------------------------------
    创建一个generator函数 名字用*标识的名字,
    都属于generator生成器函数
-->
function* fn() {
    yield 10;
    console.1og(1);
    yield 20;
    console.1og(2);
}
let gt = fn(); // 在 generator 中,执行fn方法,返回一个对象,它里面的代码不会执行
console.log(gt);
gt.next(); // 只有通过next才能控制代码一点一点的往下走
gt.next();
gt.next();
console.1og(3);

<!--输出
    object [Generator] {}
    1
    2
    3
    当只有一个 gt.next();时 只会输出 一个 3
-->

JS谁如何构建出异步编程的效果?

  • Event Loop 基于 "事件循环机制" (Event Queue 事件队列)
setTimeout(() => {
    console .1og(1);
},50);
setTimeout(() => {
    console.1og(2);
}, 0); //=>不是立即执行,有一个最小的反映时间
console. time('FOR');I
for(leti=0;i<100000;i++){}
console. timeEnd('FOR'); //=> 循环时间<=10MS
setTimeout(() => {
    console.1og(3);
}, 20);
console.1og(4);
<!--输出
    FOR:3.5ms
    4
    2
    3
    1
-->
  • Event Queue 事件队列中存在两个任务队列:

    • macro task queue 宏任务队列 (定时器、事件绑定、AJAX ... )

    • micro task queue 微任务队列 (Promise、async/await ...)

  • 只要主栈执行完,到Event Queue中去找要执行的任务

    • 执行顺序永远都是先找微任务,微任务没有了 ,再找宏任务
    • sync同步 -> micro微任务 -> macro宏任务

讲了这么多,检测一下吧

这是一个最具经典的面试题 字节跳动 今日头条

是不是题都没看明白 哈哈哈
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');

<!--输出
给了答案也不知道是个啥鬼
控制台输出:
VM90:9   script start
VM90:2 async1 start
VM90:7 async2
VM90:15 promise1
VM90:20 script end
VM90:4 async1 end
VM90:18 promise2
VM90:11 setTimeout

node下运行 
script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout
-->