Go to comments

jQuery 异步编程以及回调管理者Callbacks

一、《你不知道的js》中Ul多线程-深入剖析js执行机制

js是单线程的,单线程的意思是同一时间段只能做一件事

js单线程但是为什么能做异步的事呢?

比如一个元素绑定一个点击事件,当点击的时候变颜色,要有一个监听事件,监听什么时候被点击了,

这些js自己是办不到的,要依赖于浏览器的其它部分,


js是属于浏览器组成的一部分,离开浏览器js啥都不是(除了nodejs以外)


这几个都是异步的,js是没法异步的,

定时器

ajax

绑定事件


但是浏览器里有几个js的兄弟来帮js异步

1). 帮js查数的兄弟叫,定时器触发线程

2). 帮js处理ajax的兄弟叫,http网络请求线程

3). 帮js监听事件的叫,浏览器事件处理线程(事件监听线程)

这几个单独独立于js以外的线程跟js没关系,但是他们同属于浏览器的一部分,在js实现异步功能的时候他们起到了重要的作用


任务队列 task queue里面有很多任务,

js会看单线程里的任务都执行完了,会看task queue里面有没有任务?如果有任务拿到js线程里执行

0057.jpg


比如,

setInterval查数不是js做的,是定时器触发线程做的,

查数到时间要了要执行函数了,把任务放到 task queue 任务队列里面去,

任务队列要把里面的任务给到单线程的js里,

要等到js执行线程里的任务全执行完,才会执行task queue任务队列里面的东西


ajax异步请求

发送ajax请求,等待请求数据回来,不是js处理的,是http网络请求线程做的,

请求数据完成后,处理函数也放到 task queue 任务队列里面等待被执行


绑定事件

绑定事件是js做的,但是监听绑定事件,不是js做的如果是js做的下面什么都干不了,

所以监听事件是浏览器事件处理线程,

一旦有点击发送,把设置好的任务抛到 task queue 队里里面来,


就是js只负责执行,但是什么时候执行都是这些兄弟帮忙的,

ajax请求完数据,定时器到时间了,点击事件触发了,都会告诉单线程的js执行,


ajax发送、http请求、事件监听这些兄弟帮js做的事情的过程叫异步编程

然后异步做完事后,把要执行的任务放到 task queue 告诉js要执行这些函数了,这个函数叫回调函数


总结一下回调的意思

当处理异步的兄弟帮忙做的事,事件处理完成之后,要执行的函数叫回调函数,

换句话说当什么什么事情完事后处理的函数加回调函数


有一个关键的说法,

异步编程是离不开回调机制的,

比如事件就监听,它不干别的事,监听完也不抛方法,那监听没有什么用,它有病啊!

但凡浏览器需要异步做事情的时候,一定伴随着回调函数


部分回调是异步的,

后期高级编程的时候,有些逻辑层面的回调,从空间的角度不是异步的,那是极少数情况,

当前的ajax请求是异步的,借助浏览器其它部分做事情肯定是异步的,异步完之后必然对应一个回调机制

陈思彤老师

单线程的js使用setIntval查数,是异步的编程方式,

异步交给定时器触发线程异步的去查数,

数完数后抛给task queue,这个机制叫做回调机制,抛的函数叫回调函数


最后总结

由于js是单线程,为了让更好用户体验,所以引入的异步编程的方式,

有了异步编程是逃不掉回调的,

因为异步完之后,还是要放到js主线程里去执行,逃脱不了这样一个圈(图)


如果ajax在success里面执行,一旦回调机制嵌套多了后,层层的依赖,产生回调地狱的麻烦,以后在说

callback

除了异步编程之下需要的回调,在其它场合也会用到回调机制,

比如,之前的封装的运动函数,最后一个参数也叫callback,当物体到目标点了,执行一下回调callback,方便后面做一些事情


也就是说,在其它需要回调的逻辑的场景中,也可以使用callback,方便我们做一些后续的事件,

callback不一定是非要在异步编程中的回调叫回调函数,只不过常见的系统提供的是异步编程下的回调,回调是一个广泛的概念,不要混淆了,当做满足条件就执行也叫回调,


jQuery提供了一个工具方法$.Callbacks()

二、工具方法$.Callbacks()回调管理 

运动函数 starMove(dom, attrObj, callback) 里传一个回调函数callback,到目标点以后就执行,只执行一个函数并没有额外的功能


如果执行几个回调函数,还有执行顺序的问题,手工写的回调形式就不够强大了,需要一个工具方法管理回调,

$.Callbacks()本质上起到一个管理回调的作用,并且加上一些额外的功能,


回调地狱就是由$.callbacks()实现的$.Deferred()解决的

$.Callbacks()

$.Callbacks()执行返回一个回调对象cd,回调对象cd就像一个大筐,里面放一些我们想要回调的处理函数

var cb = $.Callbacks();

function a (){
	console.log('回调函数a执行');
} 

function b (){
	console.log('回调函数b执行');
}

cb.add(a, b);

cb.fire();

// 回调函数a执行
// 回调函数b执行

1). 对象cb里面是一个内置的数组,

     通过cb.add(a, b)把函数a、函数b放到大筐里(内置数组里)

2). 当满足一个条件,调用cb.fire()执行,

     比如满足一个条件就执行函数a或者函数b

.fire()

一般是当满足一个条件时调用cd.fire()


比如当点击按钮的时候执行cd.fire(),这里有两个回调,

1). 一个是从代码逻辑上的回调,

2). 一个是浏览器内置事件的回调


.fire()如何传递参数?

定义回调函数a和b的时候能接收参数,在调用 cb.fire() 执行的时候传递参数

var cb = $.Callbacks();

function a (x, y){
	console.log('回调函数a执行:', x, y);
}

function b (x, y){
	console.log('回调函数b执行:', x, y);
}


cb.add(a, b);


cb.fire(10, 20);


// 回调函数a执行:10 20
// 回调函数b执行:10 20

.add()

.add方法比较灵活,回调函数可以放到一个数组里

var cb = $.Callbacks();

function a (x, y){
	console.log('回调函数a执行:', x, y);
}

function b (x, y){
	console.log('回调函数b执行:', x, y);
}


cb.add([a, b]); // 可以是数组的形式

cb.fire(10, 20);


// 回调函数a执行:10 20
// 回调函数b执行:10 20


也可以先执行cd.add(a)、再在执行cd.add(b)

var cb = $.Callbacks();

function a (x, y){
	console.log('回调函数a执行:', x, y);
}

function b (x, y){
	console.log('回调函数b执行:', x, y);
}


cb.add(a);

cb.add(b);


cb.fire(10, 20);


// 回调函数a执行:10 20
// 回调函数b执行:10 20

$.Callbacks()方法的参数

once       只让回调函数执行一次,下次到目标点就不要在执行了,执行一次就好

memory 意思是带有记忆

unique    唯一无二的意思

stopOnFalse

once

先不传参数once,调用两次cd.fire() ,回调函数也执行两次

var cb = $.Callbacks();

function a (x, y){
	console.log('a回调函数执行:', x, y);
}

function b (x, y){
	console.log('回调函数b执行:', x, y);
}


cb.add(a, b);


// 执行两次
cb.fire(10, 20);
cb.fire(10, 20);


// 回调函数a执行:10 20
// 回调函数b执行:10 20
// 回调函数a执行:10 20
// 回调函数b执行:10 20


传入参数once后,调用两次cd.fire()方法,只执行一次回调函数

var cb = $.Callbacks('once');

function a (x, y){
	console.log('回调函数a执行:', x, y);
}

function b (x, y){
	console.log('回调函数b执行:', x, y);
}

cb.add(a, b);

cb.fire(10, 20);
cb.fire(10, 20);


// 回调函数a执行:10 20
// 回调函数b执行:10 20

也就是说第一次执行cd.fire()回调函数a和不一个一个执行,第二次调用cd.fire()就不好使了

memory

var cb = $.Callbacks('memory')

传参数memory,回调对象cd是带又功能是带有记忆


不传memory参数,cd.add(a, b)方法后面,只执行一次cd.fire(10, 20),后面再增加的cd.add(c)是不执行的

var cb = $.Callbacks();

function a (x, y){
	console.log('回调函数a执行:', x, y);
}

function b (x, y){
	console.log('回调函数b执行:', x, y);
}

cb.add(a, b);

cb.fire(10, 20);

function c(x, y){
	console.log('回调函数c执行:', x, y);
}

cb.add(c);


// 回调函数a执行: 10 20
// 回调函数b执行: 10 20


除非在调用一次cd.fire()

var cb = $.Callbacks();

function a (x, y){
	console.log('回调函数a执行:', x, y);
}

function b (x, y){
	console.log('回调函数b执行:', x, y);
}

cb.add(a, b);

cb.fire(10, 20);

function c(x, y){
	console.log('回调函数c执行:', x, y);
}

cb.add(c);

cb.fire(); // 除非后面在执行一次fire


// 回调函数a执行: 10 20
// 回调函数b执行: 10 20
// 回调函数a执行: undefined undefined
// 回调函数b执行: undefined undefined
// 回调函数c执行: undefined undefined


传入memory参数,只要cd.fire()操作过,.add(c)后面在加的函数c也执行了

var cb = $.Callbacks('memory');

function a (x, y){
	console.log('回调函数a执行:', x, y);
} 

function b (x, y){
	console.log('回调函数b执行:', x, y);
}


cb.add(a, b);


cb.fire(10, 20);


function c(x, y){
	console.log('c执行:', x, y);
}

cb.add(c);


// 回调函数a执行: 10 20
// 回调函数b执行: 10 20
// c执行: 10 20

unique

cd.add(a, b)执行两次,也就是说cd对象中有四个回调函数,当cd.fire()的时候执行四个回调函数

var cb = $.Callbacks();

function a (x, y){
	console.log('回调函数a执行:', x, y);
} 

function b (x, y){
	console.log('回调函数b执行:', x, y);
}

cb.add(a, b);
cb.add(a, b);

cb.fire(10, 20);


// 回调函数a执行: 10 20
// 回调函数b执行: 10 20
// 回调函数a执行: 10 20
// 回调函数b执行: 10 20


传入参数unique,unique是独一无二的意思,功能是把重复的去掉,函数a、b各执行一次,把cd.add(a, b)给去重了

var cb = $.Callbacks('unique'); 

function a (x, y){
	console.log('回调函数a执行:', x, y);
}

function b (x, y){
	console.log('回调函数b执行:', x, y);
}

cb.add(a, b);
cb.add(a, b);

cb.fire(10, 20);


// 回调函数a执行: 10 20
// 回调函数b执行: 10 20

stopOnFalse

不传参数stopOnFalse,是按顺序执行

var cb = $.Callbacks(); 

function a (x, y){
	console.log('回调函数a执行:', x, y);
} 

function b (x, y){
	console.log('回调函数b执行:', x, y);
	return false;
}

function c (x, y){
	console.log('回调函数c执行:', x, y);
}

cb.add(a, b);

cb.add(c);

cb.fire(10, 20);


// 回调函数a执行: 10 20
// 回调函数b执行: 10 20
// 回调函数c执行: 10 20


stopOnFalse参数的功能是,遇到函数的返回值是false,无论后面队列里还有什么都不执行了,b函数返回false,后面的c函数就不执行了

var cb = $.Callbacks('stopOnFalse'); 

function a (x, y){
	console.log('回调函数a执行:', x, y);
} 

function b (x, y){
	console.log('回调函数b执行:', x, y);
	return false; // 执行到这返回false,后面的c就不执行了
}

function c (x, y){
	console.log('回调函数c执行:', x, y);
}

cb.add(a, b);
cb.add(c);

cb.fire(10, 20);


// 回调函数a执行: 10 20
// 回调函数b执行: 10 20



Leave a comment 0 Comments.

Leave a Reply

换一张