在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彈出框之後,我們還沒有點選確認的時候,就重新整理了,不合常規。
例子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其它相關文章!