Javascript教程十——事件循环机制

事件循环机制

事件循环,也就是EventLoop,也就是完成一个任务会需要完成一系列的任务,因此会有一个任务队列,用循环的方式一个个执行,同时执行期间的机制依据着:

同步   >   异步

很好理解,就是同步的任务一定是排着队的一个个从前往后执行,但是异步是会比同步慢一点,这是无可厚非的,但是在异步里面也是要分先后的。

JS单线程

这里我们需要了解,JS是单线程机制程序,所谓单线程,便是同一时间,只能有一个线程任务执行,因为如果存在多个线程,那么页面的加载就完全不受控制了,不知道究竟谁会先出现,为保证页面的顺利进行,必须实行单线程机制。

因为JavaScript是单线程运行的,所有的任务只能在主线程上排队执行,这就是事件循环机制的基础——事件队列。

异步

但是我们不能保证事件队列里面的事件一定可以在合适的时间完成,举个🌰:

如果一个网络请求会去请求网络数据,需要花费20分钟,那么我们的页面要等待20分钟吗,很明显,不可以,这样就会卡住页面,我们需要实行异步,便是这个网络请求需要让出cpu,让事件队列的其他事件先执行,等我请求数据返回再占用cpu,所以这就是JS前端异步的重要,也是必须要实现的。

任务类型

任务类型主要分为两种:宏任务 marco-task 和 微任务 micro-task
在ES6中,宏任务又称为ScriptJobs,而微任务又称PromiseJobs

宏任务

宏任务在真实性况下有以下几种:

脚本(主程序代码),setTimeout,setInterval,setImmediate

微任务

微型任务的真实包含任务:

async/await,Promises

所以我们可以罗列一下任务执行的顺序:

脚本(主程序)—>Promise...--> setTimeout

举个🌰:

setTimeout(function () {
	console.log(3);
}, 0);

Promise.resolve().then(function () {
	console.log(2);
});
console.log(1);

结果是: 1、2、3
执行顺序:

主程序代码——>Promise——>setTimeOut

再举个🌰:

setTimeout(function(){console.log(1)},0); // 宏任务(排后面)

new Promise(function(resolve,reject){
	console.log(2);  // 它实际上是主程序,根本没有异步
	resolve();
}).then(function(){console.log(3)    // Promise的resolve 异步
}).then(function(){console.log(4)}); // Promise的reject 异步

process.nextTick(function(){console.log(5)});  // process.nextTick 异步

console.log(6);  //  主程序

// 输出2,6,5,3,4,1

主程序代码——>Promise——>setTimeOut

经典案例:

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

输出:

// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeOut

JS的防抖与节流

防抖

简单来讲,防抖就是当页面的一个标签被反复触发,只会让最后一次的事件一段时间后生效。

既然涉及到了时间,就需要设置一个计时器,然后计时器延时执行任务:

setTimeOut(function(){
	// 这里是要执行的操作
	func(); //  执行触发函数
}, wait); // wait 是延迟的时间

因为多次点击后,只有最后一次的可以执行,很明显,多次点击后,前面的定时器被清除了,我们来了解一下定时器的清除:

clearTimeout();

所以就是一个定时器如果存在,那么就清除它,然后从头开始一个计时器:

var timer;
if(timer != null){
	clearTimeOut(timer);
}else {
	timer = setTimeOut(function(){
		func(); 
	}, wait); 
}

然后把它们放进一个函数,因为涉及到一个存在问题,可以认为timer是一个全局变量,但是可以利用闭包放进局部变量里面:

function fangdou(func, wait){
	var timer;
	return function TimeMaker(){
		if(timer != null){
			clearTimeOut(timer);
		}else {
			timer = setTimeOut(function(){
				func(); 
			}, wait); 
	}
}

节流

节流和防抖不太一样,如果我们持续点击一个button,那么我们会让button绑定的函数在一个时间段内保证只执行一次,然后此次执行完成后就会开启另外一个时间段来执行下一次的任务,不会执行太多次,但并不是一次。简单来讲一句话,同一时间段,只让第一个操作执行。

因此可以设计一个标签,判断当前时间段有没有定时器在执行,如果有,那么就可以直接返回了,当时没有定时器,那么就可以在这个时间段申请我的事件。

function jieliu(func, wait){
	var timerTag = false;  // 没有占用
	return function TimeMaker(){
		if(timerTag){
			return; // 当前有定时器,这个时间段就不用再执行了
		}else {
			timerTag = true; // 占用这个时间段
			setTimeOut(function(){
				func(); 
				// 执行完成,可以更改标签允许下一个时间段进行任务了
				timerTag = false; // 释放允许占用
			}, wait); 
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值