js事件循环

javascript是单线程

 JavaScript的单线程,因为作为浏览器脚本语言,JavaScript的主要用途是增强用户与 Web 站点和 Web 应用程序之间的交互。这决定了它只能是单线程,否则会带来很复杂的并发问题。但是为了提高网页性能,往往js中都存在着大量的异步操作以解决js同步操作时可能会出现的浏览器的阻塞现象。 

异步的必要性 

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。这时对CPU的性能消耗就比较大,同时也会出现浏览器的阻塞现象。所以在js中,主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。所以就形成了javascriptevent loop

通常,在大多数浏览器中,每个浏览器都有一个事件循环,以使每个进程隔离,并避免web页面具有无限循环或繁重的处理来阻塞整个浏览器。

一个 event loop在初始化的时候 他的task队列是空的,并且每一个event loop 都有 a microtask checkpoint flag 也就是类似于现在整个队列中 是否有可以执行的 task的标志. 而这个标志也默认为 false

一、js的执行同步事件队列

事件循环不断检查调用堆栈以查看是否存在需要运行的任何函数。它会将它找到的任何函数调用添加到调用堆栈并按顺序执行每个调用。

const fn1= () => console.log(‘one’);
const fn2= () => console.log('two');
const fn3= () =>{
console.log(‘three');
fn1();
fn2();
};
fn3();
//输出结果:three,one,two

二、js异步操作

1、dom操作绑定事件

主线程运行的时候,栈中的代码调用各种外部API,它们在"任务队列"中加入各种事件。只要栈中的代码执行完毕,主线程就会去读取"任务队列",依次执行那些事件所对应的回调函数。执行栈中的代码(同步任务),总是在读取"任务队列"(异步任务)之前执行

window.onload=function(){
console.log('onloadwindow')
};
const fn1= () => console.log('one');
const fn2= () => console.log('two');
const fn3= () =>{
console.log('three');
fn1();
fn2();
};
fn3();
//输出结果:three,one,two,onloadwindow

2、setTimeout
setTimtout是异步事件,js队列执行时,会将处于等待中的任务存储待执行任务的队列中,当主线程的空闲下来,再去执行存储在任务队列中的任务;

const fn1= () => console.log('one');
const fn2= () => console.log('two');
const fn3 = () =>{
console.log('three');
setTimeout(()=>{
fn1();
},1000);
fn2();
};
fn3();
//输出结果:three,two,one

当设置setTimeout时间间隔为0时,或者中间间隔其他js同步操作时,输出结果都是一样的;因为异步操作会被挂起在任务队列中,当主线程任务执行完毕之后空闲下来,会从任务队列中取出执行。

3、es7 async函数

async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。

async 函数中可能会有 await 表达式,async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作完成后,恢复 async 函数的执行并返回解析值。

await 关键字仅在 async function 中有效。如果在 async function 函数体外使用 await ,你只会得到一个语法错误。

function testAwait(){
   return new Promise((resolve) => {
       setTimeout(function(){
          console.log("testAwait");
          resolve();
       }, 1000);
   });
}
async function helloAsync(){
  await testAwait();
  console.log("helloAsync");
 }
helloAsync();
//输出结果:testAwait,helloAsync

补充一下:

Promise对象

Promise 是一个对象,从它可以获取异步操作的消息

Promise 异步操作有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。除了异步操作的结果,任何其他操作都无法改变这个状态。

Promise 对象只有:从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变。只要处于 fulfilled 和 rejected ,状态就不会再变了即 resolved(已定型)。

var promise = new Promise(function(resolve, reject) { 
// 异步处理 
// 处理结束后、调用resolve 或 reject 
});

promise.then() 是 promise 最为常用的方法。then 方法接收两个函数作为参数,第一个参数是 Promise 执行成功时的回调,第二个参数是 Promise 执行失败时的回调,两个函数只会有一个被调用。

posted @ 2019-03-27 16:41  可可西里的骄傲  阅读(251)  评论(0编辑  收藏  举报