js事件循环队列

事件循环队列

JavaScript是什么

是一个单线程、非阻塞、异步、解释型的脚本语言。那是怎么实现非阻塞、异步的?这就涉及到了浏览器的事件循环机制。

关于执行中的线程:

1、问:JavaScript被浏览器执行为什么是单线程?

答:JavaScript 是浏览器脚本语言,它可以操纵 DOM ,可以渲染动画,可以与用户进行互动,如果是多线程,执行顺序无法预知,操作以哪个线程很难预知。

2、主线程:也就是 js 引擎执行的线程,这个线程只有一个,页面渲染、函数处理都在这个主线程上执行。
工作线程:也称幕后线程,这个线程可能存在于浏览器或js引擎内,与主线程是分开的,处理文件读取、网络请求等异步事件。

什么是同步任务和异步任务?

1、同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。

2、异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有 "任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

事件循环

同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入任务队列。主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。

流程如下:

1、调用栈顺序调用任务----------------------(往调用栈里面push任务,顺序执行同步任务)

2、当调用栈发现异步任务时,将异步任务交给其他模块处理,自己继续进行下面的调用

3、异步执行完毕,异步模块将任务推入任务队列,并通知调用栈

4、调用栈在执行完当前任务后,将执行任务队列里的任务----(宏变微,微进主)

5、调用栈执行完任务队列里的任务之后,继续执行其他任务

任务队列的宏任务和微任务

宏任务,大概包括:script(整体代码), setTimeout, setInterval, setImmediate(NodeJs), I/O, UI rendering。

微任务,大概包括: process.nextTick(NodeJs), Promise, Object.observe(已废弃), MutationObserver(html5新特性)

面试:说说事件循环机制

答题大纲

  1. 先说基本知识点,宏任务、微任务有哪些
  2. 说事件循环机制过程,边说边画图出来
  3. 说async/await执行顺序注意,可以把 chrome 的优化,做法其实是违反了规范的,V8 团队的PR这些自信点说出来,显得你很好学,理解得很详细,很透彻。
  4. 把node的事件循环也说一下,重复1、2、3点,node中的第3点要说的是node11前后的事件循环变动点。
    https://blog.csdn.net/LuckyWinty/article/details/104765786/

回调地狱 Callback hell

js的特性—异步编程

JavaScript 由于某种原因是被设计为单线程的,同时由于 JavaScript 在设计之初是用于浏览器的 GUI 编程,这也就需要线程不能进行阻塞,所以在后续的发展过程中基本都采用异步非阻塞的编程模式。

简单来说,异步编程就是在执行一个指令之后不是马上得到结果,而是继续执行后面的指令,等到特定的事件触发后,才得到结果。也正是因为这样,我们常常会说: JavaScript 是由事件驱动的

今日读取文件的操作中:

/* 读取文件 */
fs.readFile('a.txt',function(error,data){
  if(error){
    return console.log('读取数据失败!');
  }
  console.log('a');
});
 
fs.readFile('b.txt',function(error,data){
  if(error){
    return console.log('读取数据失败!');
  }
  console.log(‘b’);
});
 
fs.readFile('c.txt',function(error,data){
  if(error){
    return console.log('读取数据失败!');
  }
  console.log('c');
});

上面的代码是读取3个不同的文件,读取完成分别打印a、b、c

那么上面代码的打印结果有顺序吗?是 a b c 吗?

上面的代码是异步执行的,没有人敢保证打印的顺序肯定是 a b c,这就是 异步编程

什么是回调地狱

首先了解回调函数

回调函数就是一个通过函数指针调用的函数,用以处理异步参数请求,把函数内部的值返回到函数外部。它剥夺了函数return的能力。 如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

现在我们利用回调函数实现—a文件读完了再读b,b读完了再读c:

fs.readFile('a.txt',function(error,data){
  if(error){
    return console.log('读取数据失败!');
  }
  console.log('a');
 
  fs.readFile('b.txt',function(error,data){
    if(error){
      return console.log('读取数据失败!');
    }
    console.log('b');
 
    fs.readFile('c.txt',function(error,data){
      if(error){
        return console.log('读取数据失败!');
      }
      console.log('c');
    });
  });
});

虽然 这样保证了 a 读取完在读 b,b读取完再读 c 了

其实以及陷入回调地狱,一层套一层,维护起来及其困难,如果有100个文件需要读怎么办?

解决回调地狱(一): Promise

Promise的相关概念

阮一峰的Promise 对象: https://es6.ruanyifeng.com/?search=Promise&x=0&y=0#docs/promise

Promise用法:

var promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

resolve函数:作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject函数:作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

第一个回调函数是Promise对象的状态变为resolved时调用

第二个回调函数是Promise对象的状态变为rejected时调用。

其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

补充:

Promise 新建后就会立即执行。

如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给相应的回调函数。

用Promise解决回调地狱

var fs = require('fs');
 
var promise1 = new Promise(function(resolve, reject){
    fs.readFile('./a.txt',function(error,data){
        if(error){
            reject(error);
        }else{
            resolve(data);
        }
    });
});
 
var promise2 = new Promise(function(resolve, reject){
    fs.readFile('./b.txt',function(error,data){
        if(error){
            reject(error);
        }else{
            resolve(data);
        }
    });
});
 
var promise3 = new Promise(function(resolve, reject){
    fs.readFile('./c.txt',function(error,data){
        if(error){
            reject(error);
        }else{
            resolve(data);
        }
    });
});
 
promise1
    .then(
        function(data){
            console.log(data);//输出结果:a.txt 文本数据
            return promise2;
        },
        function(error){
            console.log(error);
        })
    .then(
        function(data){
            console.log(data);//输出结果:promise2的resolve函数参数数据,也就是b.txt 文本数据
            return promise3;
        },
        function(error){
            console.log(error);
        })
    .then(
        function(data){
            console.log(data);//输出结果:promise3的resolve函数参数数据,也就是c.txt 文本数据
        },
        function(error){
            console.log(error);
        });

其他解决回调地狱的方法: https://www.kancloud.cn/xiaomingjun/interview/909759

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值