JS面试知识点9-异步

异步的理解

宿主环境:浏览器环境/Node环境
我们写了一段JS代码时,浏览器或Node环境传递给JS引擎,并且要求他们去执行
所以JS引擎会常驻在内存中,等待宿主环境(我们)把JS代码传递给他去执行
ES3及其之前JS本身没有能力执行异步代码,宿主环境将代码传递给JS引擎,JS引擎就顺次执行下去,这个任务是宿主发起的
ES5之后,JS引入了Promise,不需要宿主环境安排,JS引擎本身也就可以发起任务
宿主发起的任务称之为:宏任务
JS引擎发起的任务称之为:微任务

JS引擎等待宿主环境分配宏任务,在操作系统中,等待的行为都是一个事件循环,所以在Node术语这一部分称之为:事件循环

Promise

function sleep (sec) {
    return new Promise((resolve,reject)=>{setTimeout(resolve,sec)})
};
sleep(2000).then(()=>{console.log('hello')})


async sleep (sec) {
   console.log('hello');
   await sleep(3000);
   console.log('world');
}

实现一个红绿灯,把一个圆形div按照绿色3秒,黄色1秒,红色2秒循环改变背景色

    <style>
      #test {
        border: 20px;
        width: 100px;
        height: 100px;
        background-color: #ccc;
        border-radius: 50%;
      }
    </style>  


<body>
    <div id="test"></div>
    <script>
      const light = document.getElementById( 'test' );
      console.log( light );
      function sleep( sec ) {
        return new Promise( ( resolve, reject ) => {
          setTimeout( resolve, sec );
        } )
      };
      async function shineLight() {
        while ( 1 )
        {
          light.style.backgroundColor = 'green';
          await sleep( 3000 );
          light.style.backgroundColor = 'yellow';
          await sleep( 1000 );
          light.style.backgroundColor = 'red';
          await sleep( 2000 );
        }
      }
      shineLight();
    </script>
  </body>

generator

参考:generator

function* foo(x) {
  let y = 2 * (yield (x + 1));
  let z = yield (y / 3);
  return (x + y + z);
};
let it = foo(5);
console.log('it', it);
console.log(it.next()); //{value: 6, done: false}
console.log(it.next(12)); 
console.log(it.next(13)); 
  • generator函数:
    • 交出函数的执行权(暂停执行)多线程协同执行
    • generator函数不是普通函数,
    • 是可以暂停执行的函数 ;
    • 异步操作需要暂停的地方都通过yield标注。
    • 调用函数并不执行,也不返回函数执行结果。
    • 不返回结果,而是返回一个指向内部状态的指针对象(遍历器对象)。
    • 调用next方法,内部指针从函数头部或上一次停下来的地方开始执行, 直到遇到下一个yield或return。
    • generator函数是分段执行的,yield是暂吋执行的标志,next可以恢复执行。
  • generator函数数据交换:
    • 第一个next方法,返回表达式x+2的值;
    • 第二个next方法有参数2,作为上个阶段异步任务的返回结果,被函数体内的变量y接收;
    • next的参数可以让generator函数在运行之后,还能注入值,
    • next方法参数表示上一个yield表达式的返回值,所以在第一次使用next传递参数是无效的。

async

async function async1() {
  console.log('async1 start')
  await async2() //等async2执行完毕,会阻塞后面的代码,跳出async函数,执行其他代码
  console.log('async1 end') //放入到Promise.then中的代码
}

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')

    /*
    同:‘script start’ ‘async1 start’ ‘async2’ promise1 ‘script end’
    宏:‘setTimeout’
    微:‘async1 end’ ‘promise2’
    */
  • 异步的终极解决方案

  • 就是generator加上Promise的语法糖

    • 封装了generator的执行器和返回一个Promise

  • 返回的是一个Promise
  • await后面【表达式】的可以是一个Promise也可以是一个值,但是最终都转换成resolved的Promise;
    • await 下面的代码相当于Promise的then里的代码
  • 区别generator:内置了执行器,而且语义上更好理解,将异步函数以普通同步函数的方式书写。

    • generator需要next函数触发执行

EventLoop

  • 浏览器的EventLoop
    • 执行同步代码,
    • 同步代码执行完后,执行栈为空,检查是否有异步代码需要执行,
    • 执行所有微任务,
    • 然后下一轮EventLoop,执行宏任务中的异步代码。
  • Node中的EventLoop

猜你喜欢

转载自blog.csdn.net/weixin_43374360/article/details/109160113