摘要:大部分人都知道回調(diào)函數(shù)在中被發(fā)揮的淋漓盡致,然而新手往往很少知道回調(diào)函數(shù)原理,所以接下來(lái)我們?nèi)砸赃@個(gè)栗子為代表探討回調(diào)函數(shù)。這就是對(duì)回調(diào)函數(shù)的簡(jiǎn)單講解,萌新程序員,歡迎糾錯(cuò)
JS的異步執(zhí)行機(jī)制 什么是異步執(zhí)行
為了提高Javascript代碼的運(yùn)行效率,JS對(duì)于部分函數(shù)方法采用了異步調(diào)用機(jī)制(如Ajax的操作)。異步執(zhí)行的函數(shù)方法的執(zhí)行并非為一個(gè)隊(duì)列挨個(gè)執(zhí)行的,而是相互獨(dú)立,同時(shí)調(diào)用執(zhí)行的,從而避免代碼運(yùn)行阻塞,減少不必要的等待時(shí)間。
我們來(lái)舉一個(gè)栗子大部分新手編程時(shí),都會(huì)按照一種線性思維的方法去設(shè)計(jì)代碼,這就跟JS中的異步執(zhí)行機(jī)制相沖突。
如:我們?cè)趎ode中,希望在一個(gè)讀取文檔流的操作后,將讀取到的文件中的字符串賦值給變量,str 之后再用 console.log() 方法輸出讀取到的文件內(nèi)容,這時(shí)如果按照我們的線性思維去設(shè)計(jì)代碼,會(huì)寫(xiě)出如下的操作:
// 需求:封裝一個(gè)方法,傳入一個(gè)路徑,可以讀取相對(duì)應(yīng)的文件 const fs = require("fs"); const path = require("path"); // 給定文件路徑,返回讀取到的內(nèi)容 function getFileByPath(fpath) { fs.readFile(fpath, "utf-8", (err, dataStr) => { if (err) throw err; else { var str = dataStr; } }) } // 調(diào)用讀取文件方法 getFileByPath(path.join(__dirname, "./files/1.txt")); console.log(str);
控制臺(tái)輸出的結(jié)果為
ReferenceError: str is not defined
這就是由于我們是按照線性思維去考慮問(wèn)題,理所當(dāng)然的認(rèn)為變量 str 的定義和賦值操作在 console.log() 操作之前,然而真實(shí)的情況是,JS在被解析之后,可以瞬間執(zhí)行的操作,如 console.log()、for循環(huán) 等基礎(chǔ)操作,都是按照隊(duì)列執(zhí)行的,如:
var test = function () { console.log("1"); } test(); for (var i = 2; i < 5; i++) { console.log(i); } console.log("6");
控制臺(tái)輸出的結(jié)果為
1
2
3
4
5
6
然而讀取文件操作是一個(gè)會(huì)導(dǎo)致代碼阻塞的操作,所以JS會(huì)將其放置在異步隊(duì)列中,執(zhí)行后方代碼,所以栗子中執(zhí)行代碼的正確順序應(yīng)該是先執(zhí)行console.log() 再執(zhí)行 getFileByPath()。
回調(diào)函數(shù)那倘若說(shuō)我們就是需要有一步操作,放在讀取文件之后再執(zhí)行,而不是跳過(guò)讀取文件操作直接執(zhí)行,那該怎么辦呢?
這就需要用“回調(diào)函數(shù)”的思想來(lái)拯救我們。大部分人都知道回調(diào)函數(shù)在 jQuery 中被發(fā)揮的淋漓盡致,然而新手往往很少知道回調(diào)函數(shù)原理,所以接下來(lái)我們?nèi)砸赃@個(gè)栗子為代表探討回調(diào)函數(shù)。
我們先拋開(kāi)回調(diào)函數(shù),用最原始的方法讓一些操作在讀取文件操作后執(zhí)行該怎么辦呢?那就是直接改寫(xiě)整個(gè) getFileByPath() 方法:
// 需求:封裝一個(gè)方法,傳入一個(gè)路徑,可以讀取相對(duì)應(yīng)的文件 const fs = require("fs"); const path = require("path"); // 給定文件路徑,返回讀取到的內(nèi)容 function getFileByPath(fpath) { fs.readFile(fpath, "utf-8", (err, dataStr) => { if (err) throw err; else { var str = dataStr; + console.log(str); } }) } // 調(diào)用讀取文件方法 getFileByPath(path.join(__dirname, "./files/1.txt"));
這樣我們就可以在直行完 getFileByPath 方法之后在控制臺(tái)輸出讀取的文件內(nèi)容。但是這樣的操作并不能很好的解決我們的問(wèn)題,倘若方法被封裝拿給別人使用,其他人需要更改源碼才可以實(shí)現(xiàn)功能方法,很顯然這樣并不靈活,甚至還會(huì)更改該方法原有的功能。
所以我們就需要設(shè)置一個(gè)回調(diào)函數(shù),在異步操作完成之后,再進(jìn)行我們需要的下一步的操作。
為了理解回調(diào)函數(shù)的原理,我們先將變更后的這一部分代碼分理出來(lái):
if (err) throw err; else { var str = dataStr; + console.log(str); }
可以看出,讀取完文件之后,會(huì)直行else下的操作,如果我們把 var str = dataStr; console.log(str)封裝成一個(gè)方法命名為 clg,那我們?cè)?else 之后執(zhí)行 clg() 方法就可以實(shí)現(xiàn)同樣的操作:
function getFileByPath(fpath) { fs.readFile(fpath, "utf-8", (err, dataStr) => { if (err) throw err; else { clg(dataStr); } }) } function clg(dataStr){ var str = dataStr; console.log(str); } getFileByPath(path.join(__dirname, "./files/1.txt"));
這樣我們就可以將讀取文件操作后執(zhí)行的操作放在 clg 方法中就可以執(zhí)行,這個(gè) clg() 實(shí)際上就可以稱(chēng)之為一個(gè)回調(diào)函數(shù),但是這樣還是會(huì)讓代碼變得繁雜。
我們來(lái)看一下jQuery的回調(diào)函數(shù):
$("#demo").animate({"opacity":"1"}, 1000, fucntion(){... 回調(diào)函數(shù) ..});
jQuery將回調(diào)函數(shù)作為一個(gè)參數(shù)傳入到方法中,所以我們只要在 getFileByPath() 方法中追加一個(gè)參數(shù),這個(gè)參數(shù)是一個(gè)函數(shù),我們就可以在源碼的 else 后執(zhí)行傳入的這個(gè)函數(shù),這個(gè)函數(shù)就稱(chēng)之為 "回調(diào)函數(shù)" 。
改寫(xiě)后的 getFileByPath() 方法
function getFileByPath(fpath, callback) { fs.readFile(fpath, "utf-8", (err, dataStr) => { if (err) throw err; else { callback(dataStr); } }) }
之后我們?cè)僭谡{(diào)用的時(shí)候,在參數(shù)位寫(xiě)入一個(gè)方法函數(shù),這個(gè)方法就會(huì)被傳入getFileByPath()方法內(nèi)部,等文件讀取操作完成之后再直行。
getFileByPath(path.join(__dirname, "./files/1.txt"), function(dataStr){ var str = dataStr; console.log(str); });
值得注意的是,我們?cè)谠创a中設(shè)置傳入的參數(shù)位時(shí),對(duì)回調(diào)函數(shù)設(shè)置了一個(gè)參數(shù)
callback(dataStr);
這個(gè)dataStr就是文件讀取操作讀取的文件內(nèi)容,我們將個(gè)變量傳入在callback()方法中,在調(diào)用getFileByPath()時(shí)寫(xiě)入的回調(diào)函數(shù)中就可以調(diào)用dataStr這個(gè)變量了。
這就是對(duì)回調(diào)函數(shù)的簡(jiǎn)單講解,萌新程序員,歡迎糾錯(cuò)- ??(?????)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/99622.html
摘要:并且最好是在的回調(diào)函數(shù)中調(diào)用,可以保證初始化成功了。當(dāng)我們通知端進(jìn)行初始化,并且初始化之后,里面會(huì)去遍歷中的回調(diào)函數(shù),并將當(dāng)做參數(shù)注入。里面會(huì)將里面的回調(diào)函數(shù)保存在全局對(duì)象變量中則是自增的。 緣由:網(wǎng)上其實(shí)有很多講解WebViewJavascriptBridge原理的文章,但都著重了Native端,今天從一個(gè)純前端角度出發(fā),抓住核心脈絡(luò)講解下原理,清晰明了,一文即懂。 通信的基礎(chǔ): ...
摘要:在處理異步回調(diào)函數(shù)的情況有著越來(lái)越值得推崇的方法及類(lèi)庫(kù),下面會(huì)依次介紹處理異步函數(shù)的發(fā)展史,及源碼解讀。而對(duì)象的狀態(tài),是由第一個(gè)的參數(shù)成功回調(diào)函數(shù)或失敗回調(diào)函數(shù)的返回值決定的。 函數(shù)的執(zhí)行分為同步和異步兩種。同步即為 同步連續(xù)執(zhí)行,通俗點(diǎn)講就是做完一件事,再去做另一件事。異步即為 先做一件事,中間可以去做其他事情,稍后再回來(lái)做第一件事情。同時(shí)還要記住兩個(gè)特性:1.異步函數(shù)是沒(méi)有返回值的...
摘要:否則按照正常流程處理。如果是表示是初始化環(huán)境的消息,如果是則表示是發(fā)送消息。則立即發(fā)送消息。回調(diào)主動(dòng)調(diào)用獲取注冊(cè)的函數(shù)調(diào)用中的對(duì)應(yīng)函數(shù)處理把消息從發(fā)送到,執(zhí)行具體的發(fā)送操作。處理從返回的消息。從而找到具體的實(shí)現(xiàn)執(zhí)行。 基本說(shuō)明 我們的項(xiàng)目是一個(gè)OC與javascript重度交互的app,OC與javascript交互的那部分是在WebViewJavascriptBridge的githu...
摘要:否則按照正常流程處理。如果是表示是初始化環(huán)境的消息,如果是則表示是發(fā)送消息。則立即發(fā)送消息。回調(diào)主動(dòng)調(diào)用獲取注冊(cè)的函數(shù)調(diào)用中的對(duì)應(yīng)函數(shù)處理把消息從發(fā)送到,執(zhí)行具體的發(fā)送操作。處理從返回的消息。從而找到具體的實(shí)現(xiàn)執(zhí)行。 基本說(shuō)明 我們的項(xiàng)目是一個(gè)OC與javascript重度交互的app,OC與javascript交互的那部分是在WebViewJavascriptBridge的githu...
閱讀 2511·2021-11-18 10:02
閱讀 1976·2021-11-09 09:45
閱讀 2401·2021-09-26 09:47
閱讀 1010·2021-07-23 10:26
閱讀 1063·2019-08-30 15:47
閱讀 3356·2019-08-30 15:44
閱讀 957·2019-08-30 15:43
閱讀 881·2019-08-29 13:50