vue中回調(diào)函數(shù)(callback)的用法舉例
一、介紹:
1、前提:在 js 中,函數(shù)也是對象,可以賦值給變量,可以作為參數(shù)放在函數(shù)的參數(shù)列表中,如:
var doSomething = function(a,b){ return a + b; } console.log(doSomething(2,3));
2、概念:callback 是一種特殊的函數(shù),這個(gè)函數(shù)被作為參數(shù)傳給另一個(gè)函數(shù)去調(diào)用,這樣的函數(shù)就是回調(diào)函數(shù)?;卣{(diào),顧名思義,回頭再調(diào)?;卣{(diào)與同步、異步并沒有直接的聯(lián)系,回調(diào)只是一種實(shí)現(xiàn)方式,既可以有同步回調(diào),也可以有異步回調(diào),還可以有事件處理回調(diào)和延遲函數(shù)回調(diào)。
3、語法:在大多數(shù)編程語言中,函數(shù)的形參總是從外向內(nèi)傳遞參數(shù),但在JS中,如果形參碰到“關(guān)鍵字” callback 則完全相反,它表示從內(nèi)向外反向調(diào)用某個(gè)外部函數(shù)。
二、舉例
1、舉例介紹:
(1)第一步:
var fs = require("fs"); var c function f(param) { console.log(param) } function writeFile() { fs.writeFile('input.txt', 'fs.writeFile 寫入文件的內(nèi)容', function (err) { if (!err) { console.log("文件寫入完成") c = 1 } }); } c = 0 writeFile() f(c)
打印結(jié)果為0,因?yàn)槌绦蜻\(yùn)行到writeFile()這一行的時(shí)候,是一個(gè)比較耗時(shí)的IO操作,JS碰到這種操作并不會(huì)停在原地一直等待直到函數(shù)執(zhí)行完畢,而是直接運(yùn)行下一條代碼(即f©),而此時(shí) c = 1這一行代碼其實(shí)并沒有被執(zhí)行到,所以打印出來的結(jié)果還是0 !,如果希望打印1,可以使用第二步的代碼:
(2)第二步:
var fs = require("fs"); var c function f(param) { console.log(param) } function writeFile() { fs.writeFile('input.txt', 'fs.writeFile 寫入文件的內(nèi)容', function (err) { if (!err) { console.log("文件寫入完成") c = 1 f(c) } }); } c = 0 writeFile()
這樣結(jié)果是對的,但是改成這樣并不完美,因?yàn)檫@么做就相當(dāng)于將f()寫死在writeFile()里了,如果此處我想根據(jù)不同的場景調(diào)用不同的函數(shù)還要寫幾個(gè)不同的writeFile(),而他們之間的區(qū)別僅僅是最后調(diào)用的那個(gè)函數(shù)不同,這里就體現(xiàn)callback的作用了(準(zhǔn)確地說callback并不真的是Javascript里的關(guān)鍵字,只是大家都約定成俗把callback這個(gè)單詞作為回調(diào)函數(shù)的默認(rèn)選擇)??聪率褂没卣{(diào)函數(shù)后的代碼:
(3)第三步:回調(diào)函數(shù)寫法
var fs = require("fs"); function f(param) { console.log(param) } function writeFile(callback) { //callback,表示這個(gè)參數(shù)不是一個(gè)普通變量,而是一個(gè)函數(shù) fs.writeFile('input.txt', 'fs.writeFile 寫入文件的內(nèi)容', function (err) { if (!err) { console.log("文件寫入完成") c = 1 callback(c) // 因?yàn)槲覀儌鬟M(jìn)來的函數(shù)名是f(),所以此行相當(dāng)于調(diào)用一次f(c) } }); } var c = 0 writeFile(f) // 函數(shù)f作為一個(gè)參數(shù)傳進(jìn)writeFile函數(shù)
經(jīng)過改造后的代碼出現(xiàn)了兩次callback,第一個(gè)callback出現(xiàn)在writeFile的形參里,起定義的作用,表示這個(gè)參數(shù)并不是一個(gè)普通變量,而是一個(gè)函數(shù),即所謂的“以函數(shù)為參數(shù)”。 第二個(gè)callback出現(xiàn)在c = 1下面,表示此處“執(zhí)行”從形參傳遞進(jìn)來的那個(gè)函數(shù)。這樣一來,writeFile()函數(shù)在執(zhí)行完畢之后到底調(diào)用哪個(gè)函數(shù)就變“活”了,如果我們想writeFile()函數(shù)執(zhí)行完之后并不是像第二個(gè)例子那樣只能調(diào)用f(),而是還有別的函數(shù)比如說x() y() z(),那么只需要寫成 writeFile(x),writeFile(y)… 就行了。PS: 此處并不一定非要寫為“callback”,你可以任意寫成a,b,c…callback只是一種約定俗成的寫法,它明確地告訴代碼閱讀者:此處是一個(gè)回調(diào)函數(shù)。
但是這步寫法不夠簡潔,一些函數(shù)的形參列表里直接嵌套一個(gè)函數(shù)的情況,其本質(zhì)上仍然是回調(diào)函數(shù),因?yàn)闆]有了函數(shù)名,所以也稱匿名函數(shù)??聪伦罱K的簡化寫法:
(4)第四步:匿名回調(diào)函數(shù)
var fs = require("fs"); function writeFile(callback) { fs.writeFile('input.txt', '我是通過fs.writeFile 寫入文件的內(nèi)容', function (err) { if (!err) { console.log("文件寫入完畢!") c = 1 callback(c) } }); } var c = 0 writeFile(function (param) { console.log(param) })
這是最簡潔的寫法,再舉幾個(gè)例子:
var doit = function(callback) { var a = 1, b = 2, c = 3; var t = callback(a,b,c); return t + 10; }; var d = doit(function(x,y,z){ return (x+y+z); }); console.log(d); export default { created() { this.testCallBack(); }, methods: { testCallBack() { let param = '測試' this.myCallback(param, function (arg1, arg2) { alert('這是回調(diào)' + arg1 + ' ' + arg2) }); }, myCallback(param, callback) { setTimeout(() => { alert(param) callback(param, '222'); }, 1000); } } } readImageFile(origin, quality, file) { let that = this; let fileName = file.name; let reader = new FileReader(); reader.onload = function(evt) { let base64File = evt.target.result; that.imageCompress( base64File, origin, { quality }, function(result) { let blobFile = that.dataURLtoBlob(result); let compressFile = new window.File([blobFile], fileName, { type: file.type }); that.uploadFile(compressFile); } ); }; reader.readAsDataURL(file); }, // 壓縮圖片 imageCompress(path, Orientation, obj, callback) { let img = new Image(); img.src = path; img.onload = function() { let that = this; // 默認(rèn)按比例壓縮 let imgWidth = that.width; let imgHeight = that.height; let scale = imgWidth / imgHeight; if (imgWidth > MAX_IMAGE_WIDTH) { imgWidth = MAX_IMAGE_WIDTH; imgHeight = imgWidth / scale; } let quality = obj.quality || 0.7; // 默認(rèn)圖片質(zhì)量為0.7 // 生成canvas let canvas = document.createElement('canvas'); let ctx = canvas.getContext('2d'); let anw = document.createAttribute('width'); let anh = document.createAttribute('height'); anw.nodeValue = imgWidth; anh.nodeValue = imgHeight; canvas.setAttributeNode(anw); canvas.setAttributeNode(anh); ctx.drawImage(that, 0, 0, imgWidth, imgHeight); // quality值越小,所繪制出的圖像越模糊 let base64 = canvas.toDataURL('image/jpeg', quality); // 回調(diào)函數(shù)返回base64的值 callback(base64); }; }, function doSomething(msg, callback){ alert(msg); if(typeof callback == "function") callback(); } doSomething("回調(diào)函數(shù)", function(){ alert("匿名函數(shù)實(shí)現(xiàn)回調(diào)!"); });
2、常見的回調(diào)函數(shù)例子:
三、回調(diào)函數(shù)中this的指向:
callback中的this指向window。可以使用Call和Apply函數(shù)來改變this指向,每個(gè)Javascript中的函數(shù)都有兩個(gè)方法:Call 和 Apply。這些方法被用來設(shè)置函數(shù)內(nèi)部的this對象以及給此函數(shù)傳遞變量。
舉例:
var clientData = { id: 096545, fullName: "Not Set", //setUsrName是一個(gè)在clientData對象中的方法 setUserName: function (firstName, lastName){ this.fullName = firstName + " " + lastName; } } function getUserInput(firstName, lastName, callback){ //code ..... //調(diào)用回調(diào)函數(shù)存儲(chǔ) callback(firstName, lastName); } getUserInput("Barack","Obama",clientData.setUserName); console.log(clientData.fullName); //Not Set console.log(window.fullName); //Barack Obama
在上面的代碼中,當(dāng)clientData.setUsername被執(zhí)行時(shí),this.fullName并沒有設(shè)置clientData對象中的fullName屬性,它將設(shè)置window對象中的fullName屬性。
下面我們看下Apply函數(shù)實(shí)現(xiàn),Call函數(shù)類似。(call接收的第一個(gè)參數(shù)為被用來在函數(shù)內(nèi)部當(dāng)做this的對象,傳遞給函數(shù)的參數(shù)被挨個(gè)傳遞。Apply函數(shù)的第一個(gè)參數(shù)也是在函數(shù)內(nèi)部作為this的對象,然而最后一個(gè)參數(shù)確是傳遞給函數(shù)的值的數(shù)組。)
//注意到我們增加了新的參數(shù)作為回調(diào)對象,叫做“callbackObj” function getUserInput(firstName, lastName, callback ,callbackObj){ //code ..... callback.apply(callbackObj, [firstName, lastName]); } getUserInput("Barack", "Obama", clientData.setUserName, clientData); console.log(clientData.fullName); //Barack Obama
四、回調(diào)函數(shù)的使用場景:
1、回調(diào)函數(shù)經(jīng)常使用于以下場景:
異步調(diào)用(例如讀取文件,進(jìn)行HTTP請求,動(dòng)態(tài)加載js文件,加載iframe資源后,圖片加載完成執(zhí)行回調(diào)等等)事件監(jiān)聽器/處理器setTimeout和setInterval方法一般情況:精簡代碼
2、以異步調(diào)用為例,回調(diào)函數(shù)與異步編程:回調(diào)函數(shù)是實(shí)現(xiàn)異步編程的利器,在程序運(yùn)行中,當(dāng)某些請求過程漫長,我們有時(shí)沒必要選擇等待請求完成繼續(xù)處理下一個(gè)任務(wù),這時(shí)使用回調(diào)函數(shù)進(jìn)行異步處理可以大大提高程序執(zhí)行效率。例如:AJAX請求。若是使用回調(diào)函數(shù)進(jìn)行處理,代碼就可以繼續(xù)進(jìn)行其他任務(wù),而無需空等。實(shí)際開發(fā)中,經(jīng)常在javascript中使用異步調(diào)用!下面有個(gè)使用AJAX加載XML文件的示例,并且使用了call()函數(shù),在請求對象(requested object)上下文中調(diào)用回調(diào)函數(shù)。
function fn(url, callback){ var httpRequest; //創(chuàng)建XHR httpRequest = window.XMLHttpRequest ? new XMLHttpRequest() : //針對IE進(jìn)行功能性檢測 window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : undefined; httpRequest.onreadystatechange = function(){ if(httpRequest.readystate === 4 && httpRequest.status === 200){ //狀態(tài)判斷 callback.call(httpRequest.responseXML); } }; httpRequest.open("GET", url); httpRequest.send(); } fn("text.xml", function(){ //調(diào)用函數(shù) console.log(this); / /此語句后輸出 }); console.log("this will run before the above callback."); //此語句先輸出
總結(jié)
到此這篇關(guān)于vue中回調(diào)函數(shù)(callback)的用法舉例的文章就介紹到這了,更多相關(guān)vue回調(diào)函數(shù)callback用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue3中通過ref獲取元素節(jié)點(diǎn)的實(shí)現(xiàn)
這篇文章主要介紹了vue3中通過ref獲取元素節(jié)點(diǎn)的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07vue大文件分片上傳之simple-uploader.js的使用
本文主要介紹了vue大文件分片上傳之simple-uploader.js的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05Fragment 占位組件不生成標(biāo)簽與路由組件lazyLoad案例
這篇文章主要為大家介紹了Fragment 占位組件不生成標(biāo)簽與路由組件lazyLoad案例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Vue循環(huán)遍歷選項(xiàng)賦值到對應(yīng)控件的實(shí)現(xiàn)方法
這篇文章主要介紹了Vue-循環(huán)遍歷選項(xiàng)賦值到對應(yīng)控件的實(shí)現(xiàn)方法啊,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06解決vue創(chuàng)建項(xiàng)目使用vue-router和vuex報(bào)錯(cuò)Object(...)is not a&nb
這篇文章主要介紹了解決vue創(chuàng)建項(xiàng)目使用vue-router和vuex報(bào)錯(cuò)Object(...)is not a function問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02