jquery中什麼是回撥函數

2022-11-17 22:00:50

在jquery中,回撥函數就是一個被作為引數傳遞的函數。函數A作為引數(函數參照)傳遞到另一個函數B中,並且這個函數B執行函數A,那麼函數A就叫做回撥函數;如果沒有名稱(函數表示式),就叫做匿名回撥函數。回撥函數的使用可以大大提升程式設計的效率,這使得它在現代程式設計中被非常多地使用。

前端(vue)入門到精通課程:進入學習
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:

本教學操作環境:windows7系統、jquery3.6.1版本、Dell G3電腦。

函數也是物件

想弄明白回撥函數,首先的清楚地明白函數的規則。在javascript中,函數是比較奇怪的,但它確確實實是物件。確切地說,函數是用Function()建構函式建立的Function物件。Function物件包含一個字串,字串包含函數的javascript程式碼。假如你是從C語言或者java語言轉過來的,這也許看起來很奇怪,程式碼怎麼可能是字串?但是對於javascript來說,這很平常。資料和程式碼之間的區別是很模糊的。

//可以這樣建立函數
var fn = new Function("arg1", "arg2", "return arg1 * arg2;");
fn(2, 3); //6
登入後複製

  這樣做的一個好處,可以傳遞程式碼給其他函數,也可以傳遞正則變數或者物件(因為程式碼字面上只是物件而已)。

傳遞函數作為回撥

  很容易把一個函數作為引數傳遞。

function fn(arg1, arg2, callback){
 var num = Math.ceil(Math.random() * (arg1 - arg2) + arg2);
 callback(num);  //傳遞結果
}

fn(10, 20, function(num){
 console.log("Callback called! Num: " + num); 
});    //結果為10和20之間的亂數
登入後複製

  可能這樣做看起比較麻煩,甚至有點愚蠢,為何不正常地返回結果?但是當遇上必須使用回撥函數之時,你也許就不這樣認為了!

  別擋道

  傳統函數以引數形式輸入資料,並且使用返回語句返回值。理論上,在函數結尾處有一個return返回語句,結構上就是:一個輸入點和一個輸出點。這比較容易理解,函數本質上就是輸入和輸出之間實現過程的對映。

  但是,當函數的實現過程非常漫長,你是選擇等待函數完成處理,還是使用回撥函數進行非同步處理呢?這種情況下,使用回撥函數變得至關重要,例如:AJAX請求。若是使用回撥函數進行處理,程式碼就可以繼續進行其他任務,而無需空等。實際開發中,經常在javascript中使用非同步呼叫,甚至在這裡強烈推薦使用!

  下面有個更加全面的使用AJAX載入XML檔案的範例,並且使用了call()函數,在請求物件(requested object)上下文中呼叫回撥函數。

function fn(url, callback){
 var httpRequest;    //建立XHR
 httpRequest = window.XMLHttpRequest ? new XMLHttpRequest() :   //針對IE進行功能性檢測
    window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : undefined;
 
 httpRequest.onreadystatechange = function(){
  if(httpRequest.readystate === 4 && httpRequest.status === 200){  //狀態判斷
   callback.call(httpRequest.responseXML); 
  }
 };
 httpRequest.open("GET", url);
 httpRequest.send();
}

fn("text.xml", function(){    //呼叫函數
 console.log(this);   //此語句後輸出
});

console.log("this will run before the above callback.");  //此語句先輸出
登入後複製

  我們請求非同步處理,意味著我們開始請求時,就告訴它們完成之時呼叫我們的函數。在實際情況中,onreadystatechange事件處理程式還得考慮請求失敗的情況,這裡我們是假設xml檔案存在並且能被瀏覽器成功載入。這個例子中,非同步函數分配給了onreadystatechange事件,因此不會立刻執行。

  最終,第二個console.log語句先執行,因為回撥函數直到請求完成才執行。

  上述例子不太易於理解,那看看下面的範例:

 function foo(){
 var a = 10;
 return function(){
  a *= 2;
  return a;  
 }; 
}
var f = foo();
f(); //return 20.
f(); //return 40.
登入後複製

  函數在外部呼叫,依然可以存取變數a。這都是因為javascript中的作用域是詞法性的。函數式執行在定義它們的作用域中(上述例子中的foo內部的作用域),而不是執行此函數的作用域中。只要f被定義在foo中,它就可以存取foo中定義的所有的變數,即便是foo的執行已經結束。因為它的作用域會被儲存下來,但也只有返回的那個函數才可以存取這個儲存下來的作用域。返回一個內嵌匿名函數是建立閉包最常用的手段。

回撥是什麼?

看維基的 Callback_(computer_programming) 條目:

In computer programming, a callback is a reference to a piece of executable code that is passed as an argument to other code.

jQuery檔案How jQuery Works#Callback_and_Functio...條目:

A callback is a function that is passed as an argument to another function and is executed after its parent function has completed. The special thing about a callback is that functions that appear after the "parent" can execute before the callback executes. Another important thing to know is how to properly pass the callback. This is where I have often forgotten the proper syntax.

百科:回撥函數

回撥函數就是一個通過函數指標呼叫的函數。如果你把函數的指標(地址)作為引數傳遞給另一個函數,當這個指標被用為呼叫它所指向的函數時,我們就說這是回撥函數。回撥函數不是由該函數的實現方直接呼叫,而是在特定的事件或條件發生時由另外的一方呼叫的,用於對該事件或條件進行響應。

因此,回撥本質上是一種設計模式,並且jQuery(包括其他框架)的設計原則遵循了這個模式。

在JavaScript中,回撥函數具體的定義為:函數A作為引數(函數參照)傳遞到另一個函數B中,並且這個函數B執行函數A。我們就說函數A叫做回撥函數。如果沒有名稱(函數表示式),就叫做匿名回撥函數。

因此callback 不一定用於非同步,一般同步(阻塞)的場景下也經常用到回撥,比如要求執行某些操作後執行回撥函數。

例子
一個同步(阻塞)中使用回撥的例子,目的是在func1程式碼執行完成後執行func2。

var func1=function(callback){
  //do something.
  (callback && typeof(callback) === "function") && callback();
}

func1(func2);
  var func2=function(){
}
登入後複製

非同步回撥的例子:

$(document).ready(callback);

$.ajax({
 url: "test.html",
 context: document.body
}).done(function() { 
 $(this).addClass("done");
}).fail(function() { alert("error");
}).always(function() { alert("complete"); 
});
/**
注意的是,ajax請求確實是非同步的,不過這請求是由瀏覽器新開一個執行緒請求,當請求的狀態變更時,如果先前已設定回撥,這非同步執行緒就產生狀態變更事件放到 JavaScript引擎的處理佇列中等待處理。*/
登入後複製

回撥什麼時候執行

回撥函數,一般在同步情境下是最後執行的,而在非同步情境下有可能不執行,因為事件沒有被觸發或者條件不滿足。

為什麼會需要回撥函數

把一個函數作為引數傳入到我們的主函數中,讓這個函數按照我們的想法順序進行執行。

我們希望能夠在彈出提示資訊之後,在我們進行點選確定之後,再執行一個函數內容,這個時候就會用到回撥。

因為在程式是非堵塞的,彈出訊息之後,在我們還沒在彈出框裡面進行點選確認或者選擇的時候,程式已經執行下面的語句了;

這樣我們就沒有選擇權了,不符合使用者習慣,所以我們採用回撥函數的方式;

採用了回撥函數之後,我們就把callback與主函數體合二為一了,就會是順序執行了,就可以進行選擇和點選確認了。

分開寫會導致不能對彈出框進行確認

回撥函數作為引數加入到主函數中,可以使得回撥在主函數中進行順序執行,彈出框也就可以正常了。

回撥函數的使用場合

資源載入:動態載入js檔案後執行回撥,載入iframe後執行回撥,ajax操作回撥,圖片載入完成執行回撥,AJAX等等。
DOM事件及Node.js事件基於回撥機制(Node.js回撥可能會出現多層回撥巢狀的問題)。

setTimeout的延遲時間為0,這個hack經常被用到,settimeout呼叫的函數其實就是一個callback的體現

鏈式呼叫:鏈式呼叫的時候,在賦值器(setter)方法中(或者本身沒有返回值的方法中)很容易實現鏈式呼叫,而取值器(getter)相對來說不好實現鏈式呼叫,因為你需要取值器返回你需要的資料而不是this指標,如果要實現鏈式方法,可以用回撥函數來實現setTimeout、setInterval的函數呼叫得到其返回值。由於兩個函數都是非同步的,即:他們的呼叫時序和程式的主流程是相對獨立的,所以沒有辦法在主體裡面等待它們的返回值,它們被開啟的時候程式也不會停下來等待,否則也就失去了setTimeout及setInterval的意義了,所以用return已經沒有意義,只能使用callback。callback的意義在於將timer執行的結果通知給代理函數進行及時處理。

回撥函數的傳遞

上面說了,要將函數參照或者函數表示式作為引數傳遞。

$.get('myhtmlpage.html', myCallBack);//這是對的
$.get('myhtmlpage.html', myCallBack('foo', 'bar'));//這是錯的,那麼要帶引數呢?
$.get('myhtmlpage.html', function(){//帶引數的使用函數表示式
myCallBack('foo', 'bar');
});
登入後複製

另外,最好保證回撥存在且必須是函數參照或者函數表示式:
(callback && typeof(callback) === "function") && callback();

回撥函數的使用範例

例子1

如果不用回撥,在alert彈出框之後,我們還沒有點選確認的時候,就重新整理了,不合常規。

1.png

例子2

如果不用回撥,ajax與彈出框函數分開寫,結果就會是在彈出框之後,我們還沒進行點選選擇,就已經傳送ajax了,然後再彈出彈出框,不符合我們的需求,所以不能這樣。

function ops(act,uid) {
        callback = {
          "ok":function(){
              $.ajax({
                  url:common_ops.buildWebUrl("/account/ops"),
                  type:'POST',
                  data:{
                      act:act,
                      uid:uid,
                  },
                  dataType:'json',
                  success:function(res){
                      allback = null;
                      if(res.code == 200) {
                          callback =function () {
                              window.location.reload();
                          }
                      }
                      common_ops.alert(res.msg,callback);
                  }
              });
          },
          "cancel":function(){
 
          }
};
        //記住callback是一個回撥函數
        //回撥函數是作為一個引數在函數中
        //然後在函數內部讓他執行
common_ops.confirm((act == "remove")?"確定刪除嗎?":"確定恢復嗎?",callback);
 
 
 
    //四個引數
    //第一個是資訊
    //第二個是按鈕
    //第三個是成功的方法
    //第四個是失敗的方法
    confirm:function( msg,callback ){
        callback = ( callback != undefined )?callback: { 'ok':null, 'cancel':null };
        layer.confirm( msg , {
            btn: ['確定','取消']
        }, function( index ){
            if( typeof callback.ok == "function" ){
                callback.ok();
                layer.close( index );
            }
        }, function( index ){
            if( typeof callback.cancel == "function" ){
                callback.cancel();
                layer.close( index );
            }
        });
    },
登入後複製

例子3

<!DOCTYPE html>
<html>
	<head>
 
	</head>
<body>
	<div>
		<button>按鈕</button>
	</div>
</body>
</html>
 
<script src="./jquery-3.6.1.min.js"></script>
<!-- 不用回撥的 -->
<!-- <script type="text/javascript">
	var object = {
		init:function(){
			this.eventbind();
		},
		eventbind:function(){
			$("button").click(function(){
				alert("111");
			})
			// 不用回撥這邊都看不到彈出框,更不要說點選確定了
			window.location.reload();
		}
	}
	$(document).ready(function(){
		object.init();
	})
</script> -->
 
<!-- 用回撥的 -->
<script type="text/javascript">
 
	var back = "回撥函數"
 
	function callback(){
			alert(back);
			window.location.reload();
	}
 
	var object = {
	
		main:"主函數",
 
		tanchu:function(msg,callback){
			alert(object.main);
 
			if (typeof callback == "function"){
				callback();
			}
		},
	}
 
	$(document).ready(function(){
		$("button").click(function(){
			object.tanchu("資訊",callback);
		})
	})
</script>
登入後複製

程式碼4程式碼優化

<!DOCTYPE html>
<html>
	<head>
	<meta charset="utf-8">
	</head>
<body>
	<div>
		<button id="noback">按鈕</button>
		<hr>
		<button id="hasbac">按鈕</button>
	</div>
</body>
</html>
 
<script src="./jquery-3.6.1.min.js"></script>
<!-- 不用回撥的 -->
<!-- <script type="text/javascript">
	var obje = {
		init:function(){
			this.eventbind();
		},
		eventbind:function(){
			$("#noback").click(function(){
				alert("1");
			})
			// 還沒出現111呢  已經彈出1了
	        alert("2 沒有彈出1 應該先彈出1的");
		}
	}
	$(document).ready(function(){
		obje.init();
	})
</script> -->
 
<!-- 用回撥的 -->
<script type="text/javascript">
 
	var hasbac = {
		main:"主函數",
		back:"回撥函數",
		init:function(){
			this.eventbind();
		},
 
		eventbind:function(){
			
			// 把callback讓入了tanchu方法中,就會順序執行了
			// 如果直接寫會導致直接彈出
			$("#hasbac").click(function(){
				hasbac.tanchu("點選",hasbac.callback);
			})
			// alert(hasbac.back);
			// window.location.reload();
		},
 
		// 以下兩個就是回撥函數的寫法
		tanchu:function(msg,func){
			alert(msg);
 			alert(hasbac.main);
 
			if (typeof hasbac.callback == "function"){
				hasbac.callback();
			}
		},
 
		callback:function(){
			alert(hasbac.back);
			window.location.reload();
		},
	}
	$(document).ready(function(){
		hasbac.init();
	})
</script>
登入後複製

總結總述

函數作為引數輸入到函數中,在主函數中進行順序執行,就是回撥函數。

【推薦學習:、】

以上就是jquery中什麼是回撥函數的詳細內容,更多請關注TW511.COM其它相關文章!