博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScipt 源码解析 回调函数
阅读量:5220 次
发布时间:2019-06-14

本文共 5934 字,大约阅读时间需要 19 分钟。

函数是第一类对象,这是javascript中的一个重要的概念,意味着函数可以像对象一样按照第一类管理被使用,所以在javascript中的函数:

能"存储"在变量中,能作为函数的实参被传递,能在函数中被创建,能从函数中返回

jquery中回调的设计

异步回调:

事件句柄回调:

$(document).ready(callback);

$(document).on('click',callback);

Ajax异步请求成功失败回调

$.ajax({

  url:"",

  context:document

}).done(function(){

  //成功执行

}).fail(function(){

  //失败执行

});

动画执行完毕回调

$("#a").click(function(){

  $("#b").animate({

    left:'+=50',

    opacity:0.25,

    height:'toggle'

  },5000,function(){

  这里是回调

});

});

同步回调

一个同步(阻塞)中使用回调的例子,目的是在test代码执行完成后执行回调callback

var test1 = function(callback){

  //执行长时间操作

  callback();

}

test1(function(){

  //执行回调中的方法

});

所以理解回调函数最重要的2点:

1,一个回调函数作为参数传递给另一个函数时,我们仅仅传递了函数定义,我们并没有在参数中执行函数,我们并不传递我们平时执行函数一样带有一对执行小括号的函数。

2,回调函数并不会马上被执行,他会在包含它的函数内的某个特定的时间点被"回调"。

回调的运用

我们经常会这样使用函数回调:

时间触发通知,资源加载通知,定时器延时,ajax,动画通知等等。

例1:

jquery针对Dom的处理提供了append,prepend,before,after等方法的处理,这几个方法的特征:

1,参数的传递可以是html字符串,DOM元素,元素数组或者jquery对象。

2,为了优化性能针对节点的处理需要生成文档碎片。

高层接口

before:function(){

  return this.domManip(arguments,function(elem){

  if(this.parentNode){

    this.parentNode.insertBefore(elem,this);

}

})

},

after:function(){

  return this.domManip(arguments,function(elem){

  if(this.parentNode){

    this.partentNode.insertBefore(elem,this.nextSibling);

  }

});

}

 

底层实现

domMainp:function(args,callback){

  args = concat.apply([],args);

  if(isFunction || self.doManip(args,callback));  

  if(l){

    //生成文档碎片

    fragment = jquery.buildFragment(args,this[0].ownerDocument,false,this);

    callback.call(this[i],node,i);

  }

  return this;

}

 

例子2

function Aaron(List, callback) {    setTimeout(function() {        var task;        if (task = List.shift()) {            task(); //执行函数        }        if (List.length > 0) { //递归分解            arguments.callee(List)        } else {            callback()        }    }, 25)}//调用​Aaron([    function() {        alert('a')    },    function() {        alert('b')    },    function() {        alert('c')    }], function() {    alert('callback')})// 分别弹出 ‘a’ , ‘b’ ,'c',’callback 传入一组函数参数,靠递归解析,分个执行,其实就时靠setTimeout可以把函数加入到队列末尾才执行的原理,聚合对象完全是一个整体,无法再次细分出来,所以我们需要一种方案,用来管理分离每一个独立的对象。 换成jquery提供的方式 var callbacks = $.Callbacks(); callbacks.add(function(){alert(1)};);
callbacks.add(function(){alert(2)};); callbacks.fire();//1 2 模式的实际运用 $.ajax({
  url:"",   context:document.body }).done(function(data){
  $("").html(data.a); }); 优化 $.ajax({
  url:"",   context:document.body }).done(function(data){
  pocessData();   pocessHtml();   pocessOther(); }); function pocessData(){
  //处理数据 } function pocessHtml(){
  $().html(data.a); } function pocessOther(){
  //处理其他逻辑 } 优化的好处是 分离出各种的业务函数,从而降低了代码之间的耦合度, 但是这样代码写法达不到代码复用的作用 用观察者模式 Observable.add(function(){
  //pocessdata }); Observable.add(function(){
  $().html(data.a); }) Observable.add(function(){
  //pocessOther }) $.ajax({
  url:"",   context:document.body }).done(function(data){
  Observable.fire(data); }) jquery回调对象 jquery.Callbacks是在1.7版本后加入的,主要用来进行函数队列的add,remove,fire,lock等操作, 并提供once,momory,unique,stopOnFalse四个option进行一些特殊的控制 $.Callbacks是一个工厂函数,使用函数调用(非new,他不是一个类),他又一个可选参数flags用来设置回调函数的行为,对外的接口也就是self的返回。 callbacks.add():回调列表中添加一个回调或回调的集合。 callbacks.disable():禁用回调列表中的回调 callbacks.disabled():确定回调列表是否已被禁用 callbacks.empty():从列表中删除所有的回调 callbacks.fire():用给定的参数调用所有的回调 callbacks.fired():访问给定的上下文和参数列表中的所有回调 callbacks.fireWith():访问给定的上下文和参数列表中的所有回调 callbacks.has():确定列表中是否提供一个回调 callbacks.lock():锁定当前状态的回调列表 callbacks.locked():确定回调列表是否已被锁定 callbacks.remove():从回调列表中的删除一个回调或回调集合。 源码结构 jQuery.Callbacks = function(options){
  options = typeof options === "string" ? (optionsCache[options] || createOptions(options)): jQuery.extend({},option);   //实现代码   fire = function(){}   self = {
    add : function(){},     remove : function(){},     has : function(){},     empty : function(){},     disable : funciton(){},     disabled : function(){},     lock:function(){},     locked:function(){},     fireWith:function(){},     fire:function(){}   };   return self; }; 整个结构要分为三个部分:options参数缓存,内部fire触发器的设计,外部。 参数的缓存设计:Callbacks是可以接受字符串的组合参数,可以使用空格分割
var opts = 'unique memory';var object = {}jQuery.each(opts.match(/\S+/g) || [], function(_, flag) {  object[flag] = true;});

这样的操作其实是不需要重复的,所以我们可以设计一个缓存池,用来储存重复的操作:

var optionsCache = {};function createOptions(options) {  var object = optionsCache[options] = {};  jQuery.each(options.match(rnotwhite) || [], function(_, flag) {    object[flag] = true;  });  return object;}

所以我们传递参数的时候,如果参数是字符串,我们可以直接从optionsCache缓存中去查找:

options = typeof options === "string" ?        ( optionsCache[ options ] || createOptions( options ) ) :        jQuery.extend( {}, options ); 默认回调对象设计 function  Callbacks(){
  var list = [];   var self;   self = {
    add:function(fn){
      list.push(fn);         },       fire:function(args){
        list.foreach(function(fn){
        fn(args);       })     }     }   return self; } once的设计 once的作用确保回调列表只执行(.fire())一次(像一个递延Deferrend) function fn1(val){
  console.info(1); } var cbs = $.Callbacks("once"); cbs.add(fn1); cbs.fire("foo"); cbs.fire("foo"); cbs只会执行一次,once定义是很明确的,确保这个回调列表只执行(.fire())一次,所以针对这种once的处理可以有多种不同的途径实现。 1,add的时候抛弃 2,在fire的时候抛弃多个 但是jquery是在执行第一个fire的时候直接给清空list列表了,然后在add的地方给判断下list是否存在,从而达到这样的处理。 function Callbacks(options){
  var list = [];   var self;   self = {
    add:function(){
      list,push(fn);     },     fire:function(args){
      if(list){
        list.forEach(function(fn){
          fn(args);         })         if(options === "once"){
          list = undefined;           }       }     }   }   return self; } 在fire之后,判断参数是否为once,直接把list给清理掉,所以之后的所有fire都被抛弃了,从而到达了once的效果。 jQuery.Callbacks的处理 在fire中调用了self.disable()方法 disable:function(){
  list = stack = memory = undefined;   return this; }
memory的设计 memory:保持以前的值,将添加到这个列表的后面的最新的值立即执行调用任何回调。 unique的设计 unique:确保一次只能添加一个回调 stopOnFalse stopOnFalse:当一个回调返回false时中断调用。
 

 

转载于:https://www.cnblogs.com/huangyin1213/p/6203382.html

你可能感兴趣的文章
架构图-模型
查看>>
sql常见面试题
查看>>
jQuery总结第一天
查看>>
Java -- Swing 组件使用
查看>>
Software--Architecture--DesignPattern IoC, Factory Method, Source Locator
查看>>
poj1936---subsequence(判断子串)
查看>>
黑马程序员_Java基础枚举类型
查看>>
[ python ] 练习作业 - 2
查看>>
一位90后程序员的自述:如何从年薪3w到30w!
查看>>
在.net core上使用Entity FramWork(Db first)
查看>>
System.Net.WebException: 无法显示错误消息,原因是无法找到包含此错误消息的可选资源程序集...
查看>>
UIImage 和 iOS 图片压缩UIImage / UIImageVIew
查看>>
MongoDB的数据库、集合的基本操作
查看>>
ajax向后台传递数组
查看>>
疯狂JAVA16课之对象与内存控制
查看>>
[转载]树、森林和二叉树的转换
查看>>
WPF移动Window窗体(鼠标点击左键移动窗体自定义行为)
查看>>
软件测试-----Graph Coverage作业
查看>>
django ORM创建数据库方法
查看>>
创建Oracle synonym 详解
查看>>