色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

我們?yōu)槭裁葱枰卣{(diào)函數(shù)?

GReq_mcu168 ? 來(lái)源:玩轉(zhuǎn)單片機(jī) ? 作者:玩轉(zhuǎn)單片機(jī) ? 2021-02-23 15:29 ? 次閱讀

不知你是不是也有這樣的疑惑,我們?yōu)槭裁葱枰卣{(diào)函數(shù)這個(gè)概念呢?直接調(diào)用函數(shù)不就可以了?回調(diào)函數(shù)到底有什么作用?程序員到底該如何理解回調(diào)函數(shù)?

這篇文章就來(lái)為你解答這些問(wèn)題,讀完這篇文章后你的武器庫(kù)將新增一件功能強(qiáng)大的利器。

一切要從這樣的需求說(shuō)起

假設(shè)你們公司要開(kāi)發(fā)下一代國(guó)民App“明日油條”,一款主打解決國(guó)民早餐問(wèn)題的App,為了加快開(kāi)發(fā)進(jìn)度,這款應(yīng)用由A小組和B小組協(xié)同開(kāi)發(fā)。其中有一個(gè)核心模塊由A小組開(kāi)發(fā)然后供B小組調(diào)用,這個(gè)核心模塊被封裝成了一個(gè)函數(shù),這個(gè)函數(shù)就叫make_youtiao()。如果make_youtiao()這個(gè)函數(shù)執(zhí)行的很快并可以立即返回,那么B小組的同學(xué)只需要:

調(diào)用make_youtiao()

等待該函數(shù)執(zhí)行完成

該函數(shù)執(zhí)行完后繼續(xù)后續(xù)流程

從程序執(zhí)行的角度看這個(gè)過(guò)程是這樣的:

保存當(dāng)前被執(zhí)行函數(shù)的上下文

開(kāi)始執(zhí)行make_youtiao()這個(gè)函數(shù)

make_youtiao()執(zhí)行完后,控制轉(zhuǎn)回到調(diào)用函數(shù)中

3a76bf96-74dd-11eb-8b86-12bb97331649.png

如果世界上所有的函數(shù)都像make_youtiao()這么簡(jiǎn)單,那么程序員大概率就要失業(yè)了,還好程序的世界是復(fù)雜的,這樣程序員才有了存在的價(jià)值。

現(xiàn)實(shí)并不容易

現(xiàn)實(shí)中make_youtiao()這個(gè)函數(shù)需要處理的數(shù)據(jù)非常龐大,假設(shè)有10000個(gè),那么make_youtiao(10000)不會(huì)立刻返回,而是可能需要10分鐘才執(zhí)行完成并返回。這時(shí)你該怎么辦呢?想一想這個(gè)問(wèn)題。可能有的同學(xué)會(huì)問(wèn),和剛才一樣直接調(diào)用不可以嗎,這樣多簡(jiǎn)單。是的,這樣做沒(méi)有問(wèn)題,但就像愛(ài)因斯坦說(shuō)的那樣“一切都應(yīng)該盡可能簡(jiǎn)單,但是不能過(guò)于簡(jiǎn)單”。想一想直接調(diào)用會(huì)有什么問(wèn)題?顯然直接調(diào)用的話,那么調(diào)用線程會(huì)被阻塞暫停,在等待10分鐘后才能繼續(xù)運(yùn)行。在這10分鐘內(nèi)該線程不會(huì)被操作系統(tǒng)分配CPU,也就是說(shuō)該線程得不到任何推進(jìn)。這并不是一種高效的做法。沒(méi)有一個(gè)程序員想死盯著屏幕10分鐘后才能得到結(jié)果。那么有沒(méi)有一種更加高效的做法呢?想一想我們上一篇中那個(gè)一直盯著你寫(xiě)代碼的老板(見(jiàn)《從小白到高手,你需要理解同步與異步》),我們已經(jīng)知道了這種一直等待直到另一個(gè)任務(wù)完成的模式叫做同步。如果你是老板的話你會(huì)什么都不干一直盯著員工寫(xiě)代碼嗎?因此一種更好的做法是程序員在代碼的時(shí)候老板該干啥干啥,程序員寫(xiě)完后自然會(huì)通知老板,這樣老板和程序員都不需要相互等待,這種模式被稱(chēng)為異步。回到我們的主題,這里一種更好的方式是調(diào)用make_youtiao()這個(gè)函數(shù)后不再等待這個(gè)函數(shù)執(zhí)行完成,而是直接返回繼續(xù)后續(xù)流程,這樣A小組的程序就可以和make_youtiao()這個(gè)函數(shù)同時(shí)進(jìn)行了,就像這樣:

3a8b4ac4-74dd-11eb-8b86-12bb97331649.png

在這種情況下,回調(diào)(callback)就必須出場(chǎng)了。

為什么我們需要回調(diào)callback

有的同學(xué)可能還沒(méi)有明白為什么在這種情況下需要回調(diào),別著急,我們慢慢講。假設(shè)我們“明日油條”App代碼第一版是這樣寫(xiě)的:

make_youtiao(10000);sell();可以看到這是最簡(jiǎn)單的寫(xiě)法,意思很簡(jiǎn)單,制作好油條后賣(mài)出去。

3aa0192c-74dd-11eb-8b86-12bb97331649.png

我們已經(jīng)知道了由于make_youtiao(10000)這個(gè)函數(shù)10分鐘才能返回,你不想一直死盯著屏幕10分鐘等待結(jié)果,那么一種更好的方法是讓make_youtiao()這個(gè)函數(shù)知道制作完油條后該干什么,即,更好的調(diào)用make_youtiao的方式是這樣的:“制作10000個(gè)油條,炸好后賣(mài)出去”,因此調(diào)用make_youtiao就變出這樣了:

make_youtiao(10000, sell);看到了吧,現(xiàn)在make_youtiao這個(gè)函數(shù)多了一個(gè)參數(shù),除了指定制作油條的數(shù)量外還可以指定制作好后該干什么,第二個(gè)被make_youtiao這個(gè)函數(shù)調(diào)用的函數(shù)就叫回調(diào),callback。現(xiàn)在你應(yīng)該看出來(lái)了吧,雖然sell函數(shù)是你定義的,但是這個(gè)函數(shù)卻是被其它模塊調(diào)用執(zhí)行的,就像這樣:

3aec2952-74dd-11eb-8b86-12bb97331649.png

make_youtiao這個(gè)函數(shù)是怎么實(shí)現(xiàn)的呢,很簡(jiǎn)單:

voidmake_youtiao(intnum, func call_back){// 制作油條call_back();//執(zhí)行回調(diào)}這樣你就不用死盯著屏幕了,因?yàn)槟惆裮ake_youtiao這個(gè)函數(shù)執(zhí)行完后該做的任務(wù)交代給make_youtiao這個(gè)函數(shù)了,該函數(shù)制作完油條后知道該干些什么,這樣就解放了你的程序。有的同學(xué)可能還是有疑問(wèn),為什么編寫(xiě)make_youtiao這個(gè)小組不直接定義sell函數(shù)然后調(diào)用呢?不要忘了明日油條這個(gè)App是由A小組和B小組同時(shí)開(kāi)發(fā)的,A小組在編寫(xiě)make_youtiao時(shí)怎么知道B小組要怎么用這個(gè)模塊,假設(shè)A小組真的自己定義sell函數(shù)就會(huì)這樣寫(xiě):

voidmake_youtiao(intnum){real_make_youtiao(num);sell();//執(zhí)行回調(diào)}同時(shí)A小組設(shè)計(jì)的模塊非常好用,這時(shí)C小組也想用這個(gè)模塊,然而C小組的需求是制作完油條后放到倉(cāng)庫(kù)而不是不是直接賣(mài)掉,要滿足這一需求那么A小組該怎么寫(xiě)呢?

voidmake_youtiao(intnum){real_make_youtiao(num);if(Team_B) {sell();// 執(zhí)行回調(diào)}elseif(Team_D) {store();// 放到倉(cāng)庫(kù)}}故事還沒(méi)完,假設(shè)這時(shí)D小組又想使用呢,難道還要接著添加if else嗎?這樣的話A小組的同學(xué)只需要維護(hù)make_youtiao這個(gè)函數(shù)就能做到工作量飽滿了,顯然這是一種非常糟糕的設(shè)計(jì)。所以你會(huì)看到,制作完油條后接下來(lái)該做什么不是實(shí)現(xiàn)make_youtiao的A小組該關(guān)心的事情,很明顯只有調(diào)用make_youtiao這個(gè)函數(shù)的使用方才知道。因此make_youtiao的A小組完全可以通過(guò)回調(diào)函數(shù)將接下來(lái)該干什么交給調(diào)用方實(shí)現(xiàn),A小組的同學(xué)只需要針對(duì)回調(diào)函數(shù)這一抽象概念進(jìn)行編程就好了,這樣調(diào)用方在制作完油條后不管是賣(mài)掉、放到庫(kù)存還是自己吃掉等等想做什么都可以,A小組的make_youtiao函數(shù)根本不用做任何改動(dòng),因?yàn)锳小組是針對(duì)回調(diào)函數(shù)這一抽象概念來(lái)編程的。以上就是回調(diào)函數(shù)的作用,當(dāng)然這也是針對(duì)抽象而不是具體實(shí)現(xiàn)進(jìn)行編程這一思想的威力所在。面向?qū)ο笾械亩鄳B(tài)本質(zhì)上就是讓你用來(lái)針對(duì)抽象而不是針對(duì)實(shí)現(xiàn)來(lái)編程的。

異步回調(diào)

故事到這里還沒(méi)有結(jié)束。在上面的示例中,雖然我們使用了回調(diào)這一概念,也就是調(diào)用方實(shí)現(xiàn)回調(diào)函數(shù)然后再將該函數(shù)當(dāng)做參數(shù)傳遞給其它模塊調(diào)用。但是,這里依然有一個(gè)問(wèn)題,那就是make_youtiao函數(shù)的調(diào)用方式依然是同步的,關(guān)于同步異步請(qǐng)參考《從小白到高手,你需要理解同步與異步》,也就是說(shuō)調(diào)用方是這樣實(shí)現(xiàn)的:

make_youtiao(10000, sell);// make_youtiao函數(shù)返回前什么都做不了

3aec2952-74dd-11eb-8b86-12bb97331649.png

我們可以看到,調(diào)用方必須等待make_youtiao函數(shù)返回后才可以繼續(xù)后續(xù)流程,我們?cè)賮?lái)看下make_youtiao函數(shù)的實(shí)現(xiàn):

voidmake_youtiao(intnum, func call_back){real_make_youtiao(num);call_back();//執(zhí)行回調(diào)}看到了吧,由于我們要制作10000個(gè)油條,make_youtiao函數(shù)執(zhí)行完需要10分鐘,也就是說(shuō)即便我們使用了回調(diào),調(diào)用方完全不需要關(guān)心制作完油條后的后續(xù)流程,但是調(diào)用方依然會(huì)被阻塞10分鐘,這就是同步調(diào)用的問(wèn)題所在。如果你真的理解了上一節(jié)的話應(yīng)該能想到一種更好的方法了。沒(méi)錯(cuò),那就是異步調(diào)用。反正制作完油條后的后續(xù)流程并不是調(diào)用方該關(guān)心的,也就是說(shuō)調(diào)用方并不關(guān)心make_youtiao這一函數(shù)的返回值,那么一種更好的方式是:把制作油條的這一任務(wù)放到另一個(gè)線程(進(jìn)程)、甚至另一臺(tái)機(jī)器上。如果用線程實(shí)現(xiàn)的話,那么make_youtiao就是這樣實(shí)現(xiàn)了:

voidmake_youtiao(intnum, func call_back){// 在新的線程中執(zhí)行處理邏輯create_thread(real_make_youtiao,num,call_back);}

3c078a34-74dd-11eb-8b86-12bb97331649.png

看到了吧,這時(shí)當(dāng)我們調(diào)用make_youtiao時(shí)就會(huì)立刻返回,即使油條還沒(méi)有真正開(kāi)始制作,而調(diào)用方也完全無(wú)需等待制作油條的過(guò)程,可以立刻執(zhí)行后流程:

make_youtiao(10000, sell);// 立刻返回// 執(zhí)行后續(xù)流程這時(shí)調(diào)用方的后續(xù)流程可以和制作油條同時(shí)進(jìn)行,這就是函數(shù)的異步調(diào)用,當(dāng)然這也是異步的高效之處。

新的編程思維模式

讓我們?cè)賮?lái)仔細(xì)的看一下這個(gè)過(guò)程。程序員最熟悉的思維模式是這樣的:

調(diào)用某個(gè)函數(shù),獲取結(jié)果

處理獲取到的結(jié)果

res = request();handle(res);這就是函數(shù)的同步調(diào)用,只有request()函數(shù)返回拿到結(jié)果后,才能調(diào)用handle函數(shù)進(jìn)行處理,request函數(shù)返回前我們必須等待,這就是同步調(diào)用,其控制流是這樣的:

3c1b740e-74dd-11eb-8b86-12bb97331649.png

但是如果我們想更加高效的話,那么就需要異步調(diào)用了,我們不去直接調(diào)用handle函數(shù),而是作為參數(shù)傳遞給request:

request(handle);我們根本就不關(guān)心request什么時(shí)候真正的獲取的結(jié)果,這是request該關(guān)心的事情,我們只需要把獲取到結(jié)果后該怎么處理告訴request就可以了,因此request函數(shù)可以立刻返回,真的獲取結(jié)果的處理可能是在另一個(gè)線程、進(jìn)程、甚至另一臺(tái)機(jī)器上完成。這就是異步調(diào)用,其控制流是這樣的:

3ca65a6a-74dd-11eb-8b86-12bb97331649.png

從編程思維上看,異步調(diào)用和同步有很大的差別,如果我們把處理流程當(dāng)做一個(gè)任務(wù)來(lái)的話,那么同步下整個(gè)任務(wù)都是我們來(lái)實(shí)現(xiàn)的,但是異步情況下任務(wù)的處理流程被分為了兩部分:

第一部分是我們來(lái)處理的,也就是調(diào)用request之前的部分

第二部分不是我們處理的,而是在其它線程、進(jìn)程、甚至另一個(gè)機(jī)器上處理的。

我們可以看到由于任務(wù)被分成了兩部分,第二部分的調(diào)用不在我們的掌控范圍內(nèi),同時(shí)只有調(diào)用方才知道該做什么,因此在這種情況下回調(diào)函數(shù)就是一種必要的機(jī)制了。也就是說(shuō)回調(diào)函數(shù)的本質(zhì)就是“只有我們才知道做些什么,但是我們并不清楚什么時(shí)候去做這些,只有其它模塊才知道,因此我們必須把我們知道的封裝成回調(diào)函數(shù)告訴其它模塊”。現(xiàn)在你應(yīng)該能看出異步回調(diào)這種編程思維模式和同步的差異了吧。接下來(lái)我們給回調(diào)一個(gè)較為學(xué)術(shù)的定義

正式定義

在計(jì)算機(jī)科學(xué)中,回調(diào)函數(shù)是指一段以參數(shù)的形式傳遞給其它代碼的可執(zhí)行代碼。

這就是回調(diào)函數(shù)的定義了。回調(diào)函數(shù)就是一個(gè)函數(shù),和其它函數(shù)沒(méi)有任何區(qū)別。注意,回調(diào)函數(shù)是一種軟件設(shè)計(jì)上的概念,和某個(gè)編程語(yǔ)言沒(méi)有關(guān)系,幾乎所有的編程語(yǔ)言都能實(shí)現(xiàn)回調(diào)函數(shù)。對(duì)于一般的函數(shù)來(lái)說(shuō),我們自己編寫(xiě)的函數(shù)會(huì)在自己的程序內(nèi)部調(diào)用,也就是說(shuō)函數(shù)的編寫(xiě)方是我們自己,調(diào)用方也是我們自己。但回調(diào)函數(shù)不是這樣的,雖然函數(shù)編寫(xiě)方是我們自己,但是函數(shù)調(diào)用方不是我們,而是我們引用的其它模塊,也就是第三方庫(kù),我們調(diào)用第三方庫(kù)中的函數(shù),并把回調(diào)函數(shù)傳遞給第三方庫(kù),第三方庫(kù)中的函數(shù)調(diào)用我們編寫(xiě)的回調(diào)函數(shù),如圖所示:

3cd97800-74dd-11eb-8b86-12bb97331649.png

而之所以需要給第三方庫(kù)指定回調(diào)函數(shù),是因?yàn)榈谌綆?kù)的編寫(xiě)者并不清楚在某些特定節(jié)點(diǎn),比如我們舉的例子油條制作完成、接收到網(wǎng)絡(luò)數(shù)據(jù)、文件讀取完成等之后該做什么,這些只有庫(kù)的使用方才知道,因此第三方庫(kù)的編寫(xiě)者無(wú)法針對(duì)具體的實(shí)現(xiàn)來(lái)寫(xiě)代碼,而只能對(duì)外提供一個(gè)回調(diào)函數(shù),庫(kù)的使用方來(lái)實(shí)現(xiàn)該函數(shù),第三方庫(kù)在特定的節(jié)點(diǎn)調(diào)用該回調(diào)函數(shù)就可以了。另一點(diǎn)值得注意的是,從圖中我們可以看出回調(diào)函數(shù)和我們的主程序位于同一層中,我們只負(fù)責(zé)編寫(xiě)該回調(diào)函數(shù),但并不是我們來(lái)調(diào)用的。最后值得注意的一點(diǎn)就是回調(diào)函數(shù)被調(diào)用的時(shí)間節(jié)點(diǎn),回調(diào)函數(shù)只在某些特定的節(jié)點(diǎn)被調(diào)用,就像上面說(shuō)的油條制作完成、接收到網(wǎng)絡(luò)數(shù)據(jù)、文件讀取完成等,這些都是事件,也就是event,本質(zhì)上我們編寫(xiě)的回調(diào)函數(shù)就是用來(lái)處理event的,因此從這個(gè)角度看回調(diào)函數(shù)不過(guò)就是event handler,因此回調(diào)函數(shù)天然適用于事件驅(qū)動(dòng)編程event-driven,我們將會(huì)在后續(xù)文章中再次回到這一主題。

回調(diào)的類(lèi)型

我們已經(jīng)知道有兩種類(lèi)型的回調(diào),這兩種類(lèi)型的回調(diào)區(qū)別在于回調(diào)函數(shù)被調(diào)用的時(shí)機(jī)。注意,接下來(lái)會(huì)用到同步和異步的概念,對(duì)這兩個(gè)概念不熟悉的同學(xué)可以參考上一盤(pán)文章《從小白到高手,你需要理解同步和異步》。同步回調(diào)這種回調(diào)就是通常所說(shuō)的同步回調(diào)synchronous callbacks、也有的將其稱(chēng)為阻塞式回調(diào)blocking callbacks,或者什么修飾都沒(méi)有,就是回調(diào),callback,這是我們最為熟悉的回調(diào)方式。當(dāng)我們調(diào)用某個(gè)函數(shù)A并以參數(shù)的形式傳入回調(diào)函數(shù)后,在A返回之前回調(diào)函數(shù)會(huì)被執(zhí)行,也就是說(shuō)我們的主程序會(huì)等待回調(diào)函數(shù)執(zhí)行完成,這就是所謂的同步回調(diào)。

3d4a97a6-74dd-11eb-8b86-12bb97331649.png

有同步回調(diào)就有異步回調(diào)。異步回調(diào)不同于同步回調(diào), 當(dāng)我們調(diào)用某個(gè)函數(shù)A并以參數(shù)的形式傳入回調(diào)函數(shù)后,A函數(shù)會(huì)立刻返回,也就是說(shuō)函數(shù)A并不會(huì)阻塞我們的主程序,一段時(shí)間后回調(diào)函數(shù)開(kāi)始被執(zhí)行,此時(shí)我們的主程序可能在忙其它任務(wù),回調(diào)函數(shù)的執(zhí)行和我們主程序的運(yùn)行同時(shí)進(jìn)行。既然我們的主程序和回調(diào)函數(shù)的執(zhí)行可以同時(shí)發(fā)生,因此一般情況下,主程序和回調(diào)函數(shù)的執(zhí)行位于不同的線程或者進(jìn)程中。

3d9de08c-74dd-11eb-8b86-12bb97331649.png

這就是所謂的異步回調(diào),asynchronous callbacks,也有的資料將其稱(chēng)為deferred callbacks ,名字很形象,延遲回調(diào)。從上面這兩張圖中我們也可以看到,異步回調(diào)要比同步回調(diào)更能充分的利用機(jī)器資源,原因就在于在同步模式下主程序會(huì)“偷懶”,因?yàn)檎{(diào)用其它函數(shù)被阻塞而暫停運(yùn)行,但是異步調(diào)用不存在這個(gè)問(wèn)題,主程序會(huì)一直運(yùn)行下去。因此,異步回調(diào)更常見(jiàn)于I/O操作,天然適用于Web服務(wù)這種高并發(fā)場(chǎng)景。

回調(diào)對(duì)應(yīng)的編程思維模式

讓我們用簡(jiǎn)單的幾句話來(lái)總結(jié)一下回調(diào)下與常規(guī)編程思維模式的不同。假設(shè)我們想處理某項(xiàng)任務(wù),這項(xiàng)任務(wù)需要依賴(lài)某項(xiàng)服務(wù)S,我們可以將任務(wù)的處理分為兩部分,調(diào)用服務(wù)S前的部分PA,和調(diào)用服務(wù)S后的部分PB。在常規(guī)模式下,PA和PB都是服務(wù)調(diào)用方來(lái)執(zhí)行的,也就是我們自己來(lái)執(zhí)行PA部分,等待服務(wù)S返回后再執(zhí)行PB部分。但在回調(diào)這種方式下就不一樣了。在這種情況下,我們自己來(lái)執(zhí)行PA部分,然后告訴服務(wù)S:“等你完成服務(wù)后執(zhí)行PB部分”。因此我們可以看到,現(xiàn)在一項(xiàng)任務(wù)是由不同的模塊來(lái)協(xié)作完成的。即:

常規(guī)模式:調(diào)用完S服務(wù)后后我去執(zhí)行X任務(wù),

回調(diào)模式:調(diào)用完S服務(wù)后你接著再去執(zhí)行X任務(wù),

其中X是服務(wù)調(diào)用方制定的,區(qū)別在于誰(shuí)來(lái)執(zhí)行。

為什么異步回調(diào)越來(lái)越重要

在同步模式下,服務(wù)調(diào)用方會(huì)因服務(wù)執(zhí)行而被阻塞暫停執(zhí)行,這會(huì)導(dǎo)致整個(gè)線程被阻塞,因此這種編程方式天然不適用于高并發(fā)動(dòng)輒幾萬(wàn)幾十萬(wàn)的并發(fā)連接場(chǎng)景,針對(duì)高并發(fā)這一場(chǎng)景,異步其實(shí)是更加高效的,原因很簡(jiǎn)單,你不需要在原地等待,因此從而更好的利用機(jī)器資源,而回調(diào)函數(shù)又是異步下不可或缺的一種機(jī)制。

回調(diào)地獄,callback hell

有的同學(xué)可能認(rèn)為有了異步回調(diào)這種機(jī)制應(yīng)付起一切高并發(fā)場(chǎng)景就可以高枕無(wú)憂了。實(shí)際上在計(jì)算機(jī)科學(xué)中還沒(méi)有任何一種可以橫掃一切包治百病的技術(shù),現(xiàn)在沒(méi)有,在可預(yù)見(jiàn)的將來(lái)也不會(huì)有,一切都是妥協(xié)的結(jié)果。那么異步回調(diào)這種機(jī)制有什么問(wèn)題呢?實(shí)際上我們已經(jīng)看到了,異步回調(diào)這種機(jī)制和程序員最熟悉的同步模式不一樣,在可理解性上比不過(guò)同步,而如果業(yè)務(wù)邏輯相對(duì)復(fù)雜,比如我們處理某項(xiàng)任務(wù)時(shí)不止需要調(diào)用一項(xiàng)服務(wù),而是幾項(xiàng)甚至十幾項(xiàng),如果這些服務(wù)調(diào)用都采用異步回調(diào)的方式來(lái)處理的話,那么很有可能我們就陷入回調(diào)地獄中。舉個(gè)例子,假設(shè)處理某項(xiàng)任務(wù)我們需要調(diào)用四個(gè)服務(wù),每一個(gè)服務(wù)都需要依賴(lài)上一個(gè)服務(wù)的結(jié)果,如果用同步方式來(lái)實(shí)現(xiàn)的話可能是這樣的:

a= GetServiceA();b= GetServiceB(a);c= GetServiceC(b);d= GetServiceD(c);代碼很清晰,很容易理解有沒(méi)有。我們知道異步回調(diào)的方式會(huì)更加高效,那么使用異步回調(diào)的方式來(lái)寫(xiě)將會(huì)是什么樣的呢?

GetServiceA(function(a){GetServiceB(a,function(b){GetServiceC(b,function(c){GetServiceD(c,function(d){....});});});});我想不需要再?gòu)?qiáng)調(diào)什么了吧,你覺(jué)得這兩種寫(xiě)法哪個(gè)更容易理解,代碼更容易維護(hù)呢?博主有幸曾經(jīng)維護(hù)過(guò)這種類(lèi)型的代碼,不得不說(shuō)每次增加新功能的時(shí)候恨不得自己化為兩個(gè)分身,一個(gè)不得不去重讀一邊代碼;另一個(gè)在一旁罵自己為什么當(dāng)初選擇維護(hù)這個(gè)項(xiàng)目。異步回調(diào)代碼稍不留意就會(huì)跌到回調(diào)陷阱中,那么有沒(méi)有一種更好的辦法既能結(jié)合異步回調(diào)的高效又能結(jié)合同步編碼的簡(jiǎn)單易讀呢?幸運(yùn)的是,答案是肯定的,我們會(huì)在后續(xù)文章中詳細(xì)講解這一技術(shù)。

總結(jié)

在這篇文章中,我們從一個(gè)實(shí)際的例子出發(fā)詳細(xì)講解了回調(diào)函數(shù)這種機(jī)制的來(lái)龍去脈,這是應(yīng)對(duì)高并發(fā)、高性能場(chǎng)景的一種極其重要的編碼機(jī)制,異步加回調(diào)可以充分利用機(jī)器資源,實(shí)際上異步回調(diào)最本質(zhì)上就是事件驅(qū)動(dòng)編程,這是我們接下來(lái)要重點(diǎn)講解的內(nèi)容。

原文標(biāo)題:10張圖讓你徹底理解回調(diào)函數(shù)

文章出處:【微信公眾號(hào):玩轉(zhuǎn)單片機(jī)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4329

    瀏覽量

    62576

原文標(biāo)題:10張圖讓你徹底理解回調(diào)函數(shù)

文章出處:【微信號(hào):mcu168,微信公眾號(hào):硬件攻城獅】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    定時(shí)器回調(diào)函數(shù)能不能用ICACHE_FLASH_ATTR定義?

    非 OS SDK 在中斷處理函數(shù)中,請(qǐng)勿使用任何 ICACHE_FLASH_ATTR 定義的函數(shù)。 請(qǐng)問(wèn): 1、定時(shí)器和hw定時(shí)器的回調(diào)函數(shù)是否在中斷處理
    發(fā)表于 07-22 06:33

    ESP8266收到重傳的UDP數(shù)據(jù)包,則udp接收回調(diào)函數(shù)會(huì)調(diào)用兩次,怎么解決?

    UDP 數(shù)據(jù)包的 payload 在回調(diào)函數(shù)中完全相同) 有幾種方法可以解決這個(gè)問(wèn)題。但是我們的應(yīng)用程序解決方案需要一個(gè)大的內(nèi)存池。 我認(rèn)為這個(gè)問(wèn)題應(yīng)該在無(wú)線驅(qū)動(dòng)程序中得到解決。
    發(fā)表于 07-18 06:29

    esp8266怎么找到回調(diào)函數(shù)被調(diào)用的地方?

    esp8266里的程序怎么運(yùn)行? 在user_init里注冊(cè)了espconn_regist_sentcb,espconn_regist_recvcb這幾個(gè)回調(diào)函數(shù),怎么找到這幾個(gè)回調(diào)函數(shù)
    發(fā)表于 07-10 08:24

    在HTTP的demo里面,回調(diào)函數(shù)不執(zhí)行的原因?

    在HTTP的demo里面,我用下面這個(gè)函數(shù)注冊(cè)了一個(gè)回調(diào)函數(shù),但是發(fā)現(xiàn)有時(shí)候正常執(zhí)行有時(shí)候不執(zhí)行,只是偶爾不執(zhí)行,大部分時(shí)間是正常的。有沒(méi)有人能提供一下原因可能的方向,謝謝!! espconn_regist_write_fin
    發(fā)表于 07-10 08:23

    定時(shí)器做PWM輸出時(shí),定時(shí)器回調(diào)函數(shù)只能執(zhí)行一次,是什么原因?

    定時(shí)器做PWM輸出時(shí),初始化定時(shí)器時(shí)執(zhí)行HAL_TIM_PWM_Init( TIM1_Handler);時(shí)進(jìn)入回調(diào)函數(shù)里初始化GPIO引腳;如果需要再重新初始化一次定時(shí)器時(shí),在執(zhí)行上面這行初始化時(shí),程序并不再進(jìn)入回
    發(fā)表于 05-30 07:15

    為什么無(wú)法停止使用cy_wcm_connect 的rtos定時(shí)器回調(diào)函數(shù)

    。 由于 cy_wcm_connect() 函數(shù)的某些原因,計(jì)時(shí)器無(wú)法停止。 取而代之的是調(diào)用回調(diào)函數(shù),由于設(shè)備已連接到 Wifi,它將再次嘗試停止計(jì)時(shí)器。 我想知道如何以正確的方式停止計(jì)時(shí)器。 我測(cè)試了使用和不使用 cy_wc
    發(fā)表于 05-24 06:34

    歐姆表機(jī)械調(diào)零和歐姆調(diào)零是什么意思

    歐姆表是一種用于測(cè)量電阻的電子測(cè)試儀器,其測(cè)量原理基于歐姆定律。在使用歐姆表測(cè)量電阻之前,通常需要進(jìn)行兩種調(diào)零操作:機(jī)械調(diào)零和歐姆調(diào)零。這
    的頭像 發(fā)表于 05-13 17:34 ?8575次閱讀

    stm32cubemx生成rtos后中斷處理后執(zhí)行的回調(diào)函數(shù)是否也有優(yōu)先級(jí)?

    如題:回調(diào)函數(shù)是否也有優(yōu)先級(jí),我發(fā)現(xiàn)我的回調(diào)函數(shù)不能按照預(yù)想的來(lái)運(yùn)行.
    發(fā)表于 04-25 08:16

    請(qǐng)問(wèn)ucos-III中斷保護(hù)放在中斷回調(diào)函數(shù)還是中斷里面?

    請(qǐng)教下ucos-III 中斷保護(hù)放在中斷回調(diào)函數(shù)還是中斷里面? 1. 中斷函數(shù) void DMA2_Stream6_IRQHandler(void) { OS_ERRerr
    發(fā)表于 04-23 07:44

    Stm32G474 DMA傳輸全部完畢后,需要產(chǎn)生中斷并調(diào)運(yùn)回調(diào)函數(shù)完成相關(guān)操作,如何處理?

    Stm32G474,DMA傳輸全部完畢后,需要產(chǎn)生中斷并調(diào)運(yùn)回調(diào)函數(shù)完成相關(guān)操作。請(qǐng)問(wèn)我如何處理?沒(méi)有看到常規(guī)的回調(diào)函數(shù)(例如這樣的HAL_
    發(fā)表于 03-15 08:26

    調(diào)函數(shù)(callback)是什么?回調(diào)函數(shù)的實(shí)現(xiàn)方法

    調(diào)函數(shù)是一種特殊的函數(shù),它作為參數(shù)傳遞給另一個(gè)函數(shù),并在被調(diào)用函數(shù)執(zhí)行完畢后被調(diào)用。回調(diào)
    發(fā)表于 03-12 11:46 ?2905次閱讀

    函數(shù)指針與回調(diào)函數(shù)的應(yīng)用實(shí)例

    通常我們說(shuō)的指針變量是指向一個(gè)整型、字符型或數(shù)組等變量,而函數(shù)指針是指向函數(shù)函數(shù)指針可以像一般函數(shù)一樣,用于調(diào)用
    的頭像 發(fā)表于 03-07 11:13 ?400次閱讀
    <b class='flag-5'>函數(shù)</b>指針與回<b class='flag-5'>調(diào)</b><b class='flag-5'>函數(shù)</b>的應(yīng)用實(shí)例

    ??嵌入式中回調(diào)函數(shù)的實(shí)現(xiàn)方法

    調(diào)函數(shù)的命名規(guī)范沒(méi)有固定的標(biāo)準(zhǔn),但是根據(jù)通用慣例和編碼規(guī)范,回調(diào)函數(shù)的命名應(yīng)該能夠反映函數(shù)的作用和功能,讓其他開(kāi)發(fā)者能夠快速理解并使用。
    發(fā)表于 03-04 14:49 ?713次閱讀

    內(nèi)聯(lián)函數(shù)定義 為什么需要內(nèi)聯(lián)函數(shù)

    inline關(guān)鍵字是C99標(biāo)準(zhǔn)的型關(guān)鍵字,其作用是將函數(shù)展開(kāi),把函數(shù)的代碼復(fù)制到每一個(gè)調(diào)用處。
    的頭像 發(fā)表于 02-19 12:20 ?540次閱讀

    ADSP-BF70x API的GPIO Server中為什么需要分配內(nèi)存空間給回調(diào)函數(shù)?

    我在使用adsp-bf70x的api時(shí)發(fā)現(xiàn),在adi_gpio_Init()調(diào)用后為回調(diào)函數(shù)分配了內(nèi)存空間。這里為什么需要這樣做,我不太明白,請(qǐng)大家?guī)兔忉屢幌拢x謝!
    發(fā)表于 01-12 08:28
    主站蜘蛛池模板: 内射人妻骚骚骚| 永久免费在线视频| 农民工老头在出租屋嫖老熟女| 久久中文字幕亚洲精品最新| 欧美乱妇狂野欧美在线视频| 三级色视频| 亚洲高清无码在线 视频| 亚洲中文字幕国产综合| chinese黑人第一次| 国产色婷婷精品人妻蜜桃成熟 | 亚洲精品偷拍影视在线观看| 欲插爽乱浪伦骨| 嘟嘟嘟影院免费观看视频| 狠狠色狠狠色综合曰曰| 女教师二十三岁| 亚洲AV无码影院在线播放| 57PAO强力打造高清免费| 国产GV无码A片在线观看| 久久国产亚洲精品AV麻豆| 秋霞鲁丝片Av无码| 亚洲色欲色欲www474ee| 超碰超碰视频在线观看| 久久vs国产综合色| 色小姐电影qvod播放| 伊人影院综合在线| 国产黄a三级三级三级| 美女伸开两腿让我爽| 亚洲精品高清AV在线播放| jizz老太婆| 久久一级片| 亚洲国产cao| 打开双腿狠狠蹂躏蜜桃臀| 乱xxxjapanese黑人| 亚洲破处女| 国产精品内射久久久久欢欢| 欧美整片华人play| 2019午夜福合集不打码| 红色机尾快播| 无限好资源免费观看| 朝鲜黄色录像| 欧美精品色视频|