大家好,我是IT修真院成都分院第09期学员。今天分享的内容是js中回调函数?
1.背景介绍
在我们接触ajax,与angularjs中的数据请求时,我们总是听到里面的回调函数,callback。我们在使用的过程中总感觉它是一个混淆的概念,它仿佛是ajax请求后调用的那个函数,又感觉它是某一个函数的形参而已。在后面angular和promise的学习中,我们会遇到非常多的回调函数,因此我们有必要弄清其中的概念
2.知识剖析
我们都知道js是单线程的,这种设计模式给我们带来了很多的方便之处,我们不需要考虑各个线程之间的通信,也不需要写很多烧脑的代码,也就是说js的引擎只能一件一件事的去完成和执行相关的操作,所以所有需要执行的事情都像排队一样,等待着被触发和执行,可是如果这样的话,如果在队列中有一件事情需要花费很多的时间,那么后面的任务都将处于一种等待状态,有时甚至会出现浏览器假死现象,例如其中有一件正在执行的一个任务是一个死循环,那么会导致后续其他的任务无法正常执行,所以js在同步机制的缺陷下设计出了异步模式
在异步执行的模式下,每一个异步的任务都有其自己一个或着多个回调函数,这样当前在执行的异步任务执行完之后,不会马上执行事件队列中的下一项任务,而是执行它的回调函数,而下一项任务也不会等当前这个回调函数执行完,因为它也不能确定当前的回调合适执行完毕,只要引它被触发就会执行
1.搞清楚异步和同步
1.早上起来不论你是先刷牙还是先洗脸,都要等一个事情完毕后才能进行下一项,这就是一个同步的例子
2.然后刷牙的时候你也可以烧水喝 (不用等你刷完牙)这就是一个异步的例子
function a(){
console.log("执行函数a");
setTimeout(function(){
console.log('执行a的延迟函数')
},1000)
}
function b(){
console.log('执行函数b')
}
a();
b();
调用 setTimeout 函数会在一个时间段过去后在队列中添加一个消息。这个时间段作为函数的第二个参数被传入。如果队列中没有其它消息,消息会被马上处理。但是,如果有其它消息,setTimeout 消息必须等待其它消息处理完。因此第二个参数仅仅表示最少的时间 而非确切的时间
var a=0;
function change() {
a=1;
}
function after(){
console.log(a);
}
change();
after();
2.回调函数到底是什么?
A callback is a function that is passed as an argument to another function and is executed after its parent function has completed.
3.回调函数是怎么运作的
因为函数在Javascript中是第一类对象,我们像对待对象一样对待函数,因此我们能像传递变量一样传递函数,在函数中返回函数,在其他函数中使用函数。当我们将一个回调函数作为参数传递给另一个函数是,我们仅仅传递了函数定义。我们并没有在参数中执行函数。我们并不传递像我们平时执行函数一样带有一对执行小括号()的函数。
人话:字面上理解下来就是,回调就是一个函数的调用过程。那么就从理解这个调用过程开始吧。函数a有一个参数,这个参数是个函数b,当函数a执行完以后执行函数b。那么这个过程就叫回调。
这里必须清楚一点:函数b是你以参数形式传给函数a的,那么函数b就叫回调函数。
3、常见问题
1.为什么写回调函数
2.回调函数一定要以参数形式传过去吗,我不可以直接在函数a里面调用函数b吗?
4、解决方案
function a(callback)
{
console.log("我是parent函数a!");
console.log("调用回调函数");
callback();
}
function b(){
console.log("我是回调函数b");
}
function c(){
console.log("我是回调函数c");
}
function test()
{
a(b);
a(c);
}
test();
如果你直接在函数a里调用的话,那么这个回调函数就被限制死了。但是使用函数做参数就有下面的好处:当你a(b)的时候函数b就成了回调函数,而你还可以a(c)这个时候,函数c就成了回调函数。如果你写成了function a(){...;b();}就失去了变量的灵活性。
启示:函数在javascript中和数据一样,可以赋值,删除,拷贝,自然也可以作为函数的参数
5.扩展思考
回调函数与ES6中的promise
6.参考文献
7、更多讨论
问题1:能否利用回调函数避免angular ajax异步请求延时导致的注入错误
答:$http 请求时间太长,就会导致注入错误
问题2:实现异步是js,还是宿主浏览器?
答:JS的单线程是指一个浏览器进程中只有一个JS的执行线程,同一时刻内只会有一段代码在执行(你可以使用IE的标签式浏览试试看效果,这时打开的多个页面使用的都是同一个JS执行线程,如果其中一个页面在执行一个运算量较大的function时,其他窗口的JS就会停止工作)。
而异步机制是浏览器的两个或以上常驻线程共同完成的,例如异步请求是由两个常驻线程:JS执行线程和事件触发线程共同完成的,JS的执行线程发起异步请求(这时浏览器会开一条新的HTTP请求线程来执行请求,这时JS的任务已完成,继续执行线程队列中剩下的其他任务),然后在未来的某一时刻事件触发线程监视到之前的发起的HTTP请求已完成,它就会把完成事件插入到JS执行队列的尾部等待JS处理。又例如定时触发(settimeout和setinterval)是由浏览器的定时器线程执行的定时计数,然后在定时时间把定时处理函数的执行请求插入到JS执行队列的尾端(所以用这两个函数的时候,实际的执行时间是大于或等于指定时间的,不保证能准确定时的)。
所以,所谓的JS的单线程和异步更多的应该是属于浏览器的行为,他们之间没有冲突,更不是同一种事物,没有什么区别不区别的。
问题3:js每次只执行一个任务,他是如何实现异步的?
答:见代码
鸣谢
感谢大家观看!
------------------------------------------------------------------------------------------------------------------------
技能树.IT修真院
“我们相信人人都可以成为一个工程师,现在开始,找个师兄,带你入门,掌控自己学习的节奏,学习的路上不再迷茫”。
这里是技能树.IT修真院,成千上万的师兄在这里找到了自己的学习路线,学习透明化,成长可见化,师兄1对1免费指导。快来与我一起学习吧 !