成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

javascript異步中的回調(diào)

WalkerXu / 3173人閱讀

摘要:如果你把函數(shù)的指針地址作為參數(shù)傳遞給另一個函數(shù),當(dāng)這個指針被用來調(diào)用其所指向的函數(shù)時,我們就說這是回調(diào)函數(shù)?;卣{(diào)函數(shù)不是由該函數(shù)的實現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時由另外的一方調(diào)用的,用于對該事件或條件進行響應(yīng)。

同期異步系列文章推薦
談一談javascript異步
javascript異步與promise
javascript異步之Promise.all()、Promise.race()、Promise.finally()
javascript異步之Promise.resolve()、Promise.reject()
javascript異步之Promise then和catch
javascript異步之a(chǎn)sync(一)
javascript異步之a(chǎn)sync(二)
javascript異步實戰(zhàn)
javascript異步總結(jié)歸檔

我們之前介紹了javascript異步的相關(guān)內(nèi)容,我們知道javascript以同步,單線程的方式執(zhí)行主線程代碼,將異步內(nèi)容放入事件隊列中,當(dāng)主線程內(nèi)容執(zhí)行完畢就會立即循環(huán)事件隊列,直到事件隊列為空,當(dāng)用產(chǎn)生用戶交互事件(鼠標(biāo)點擊,點擊鍵盤,滾動屏幕等待),會將事件插入事件隊列中,然后繼續(xù)執(zhí)行。
處理異步邏輯最常用的方式是什么?沒錯這就是我們今天要說的---回調(diào)

js回調(diào)函數(shù)

如你所知,函數(shù)是對象,所以可以存儲在變量中,
所以函數(shù)還有以下身份:

可以作為函數(shù)的參數(shù)

可以在函數(shù)中創(chuàng)建

可以在函數(shù)中返回

當(dāng)一個函數(shù)a以一個函數(shù)作為參數(shù)或者以一個函數(shù)作為返回值時,那么函數(shù)a就是高階函數(shù)
回調(diào)函數(shù)
百度百科

回調(diào)函數(shù)就是一個通過函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個函數(shù),當(dāng)這個指針被用來調(diào)用其所指向的函數(shù)時,我們就說這是回調(diào)函數(shù)。回調(diào)函數(shù)不是由該函數(shù)的實現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時由另外的一方調(diào)用的,用于對該事件或條件進行響應(yīng)。

維基百科

在計算機程序設(shè)計中,回調(diào)函數(shù),或簡稱回調(diào)(Callback 即call then back 被主函數(shù)調(diào)用運算后會返回主函數(shù)),是指通過函數(shù)參數(shù)傳遞到其它代碼的,某一塊可執(zhí)行代碼的引用。這一設(shè)計允許了底層代碼調(diào)用在高層定義的子程序。

回調(diào)函數(shù),幾乎每天我們都在用

      setTimeout(() => {
        console.log("這是回調(diào)函數(shù)");
      }, 1000);
      const hero=["郭靖","黃蓉"]
      hero.forEach(item=>{
        console.log(item);
      })
回調(diào)函數(shù)解決了哪些問題

舉一個簡單的:

      let girlName = "裘千尺"

      function hr() {
        girlName = "黃蓉"
        console.log(`我是${girlName}`);
      }

      function gj() {
        console.log(`${girlName}你好,我是郭靖,認識一下吧`);
      }
      hr()
      gj()

輸出,重點看輸出順序

//=>我是黃蓉
//=>黃蓉你好,我是郭靖,認識一下吧

上面的代碼輸出是沒什么懸念的,不存在異步,都單線程同步執(zhí)行,最后郭靖和黃蓉相識
如果這時候黃蓉很忙,出現(xiàn)了異步,會怎么樣?

      let girlName = "裘千尺"

      function hr() {
        setTimeout(() => {
          girlName = "黃蓉"
          console.log("我是黃蓉");
        }, 0);
      }

      function gj() {
        console.log(`${girlName}你好,我是郭靖,認識一下吧`);
      }
      hr()
      gj()

輸出,重點看輸出順序

//=>裘千尺你好,我是郭靖,認識一下吧
//=>我是黃蓉

雖然定時器是0ms,但是也導(dǎo)致了郭靖和黃蓉的擦肩而過,這不是我們期望的結(jié)果,hr函數(shù)存在異步,只有等主線程的內(nèi)容走完,才能走異步函數(shù)
所以最簡單的辦法就是使用回調(diào)函數(shù)解決這種問題,gj函數(shù)依賴于hr函數(shù)的執(zhí)行結(jié)果,所以我們把gj作為hr的一個回調(diào)函數(shù)

      let girlName = "裘千尺"

      function hr(callBack) {
        setTimeout(() => {
          girlName = "黃蓉"
          console.log("我是黃蓉");
          callBack()
        }, 0);
      }

      function gj() {
        console.log(`${girlName}你好,我是郭靖,認識一下吧`);
      }
      hr(gj)

輸出,重點看輸出順序

//=>我是黃蓉
//=>黃蓉你好,我是郭靖,認識一下吧

??:當(dāng)回調(diào)函數(shù)作為參數(shù)時,不要帶后面的括號!我們只是傳遞函數(shù)的名稱,不是傳遞函數(shù)的執(zhí)行結(jié)果
上面小栗子貌似的很簡單,我們繼續(xù)

嵌套回調(diào)和鏈?zhǔn)交卣{(diào)

我們把昨天的demo做一下升級
引入了lodash:處理按鈕點擊防抖
axios,集成了promis,但promise不是我們今天討論的內(nèi)容,我們只使用axios的ajax請求接口功能
easy-mock:接口數(shù)據(jù),用來實現(xiàn)ajax請求(數(shù)據(jù)是假的,但是請求是真的)

嵌套回調(diào)




  
  
  
  javascript回調(diào)
  
  



  
  


仔細看代碼,不難發(fā)現(xiàn),這是一個典型的嵌套回調(diào),我們分析一下
第一層異步,用戶交互,來自按鈕的點擊事件
第二層異步,按鈕去抖,來自lodash下debounce的500ms延時
第三次異步,ajax請求,處理后臺接口數(shù)據(jù)
拿到數(shù)據(jù)后我們沒有繼續(xù)做處理,在實際工作中可能還存在異步,還會繼續(xù)嵌套,會形成一個三角形的縮進區(qū)域

再繼續(xù)嵌套,就會形成所說的“回調(diào)地獄”,就是回調(diào)的層級太多了,代碼維護成本會高很多
上面的栗子最多算是入門毀掉地獄,我們看一下這個

      function funA(callBack) {
        console.log("A");
        setTimeout(() => {
          callBack()
        }, 10);
      }

      function funB() {
        console.log("B");
      }

      function funC(callBack) {
        console.log("C");
        setTimeout(() => {
          callBack()
        }, 100);
      }

      function funD() {
        console.log("D");
      }

      function funE() {
        console.log("E");
      }

      function funF() {
        console.log("F");
      }
//從這里開始執(zhí)行
      funA(() => {
        funB()
        funC(() => {
          funD()
        })
        funE()
      })
      funF()

(這段代碼,帶回調(diào)的都是異步邏輯)你能很快的看出這段代碼的執(zhí)行順序嗎?
順序如下:A、F、B、C、E、D
一般正常人不會這么嵌套多層,層級一多,就會考慮拆分

鏈?zhǔn)交卣{(diào)
      const btn = document.querySelector("button")
      //監(jiān)聽按鈕點擊事件
      btn.onclick = () => {
        debounceFun()
      }
      //去抖動
      const debounceFun = _.debounce(() => {
        ajax()
      }, 500)
      //ajax 請求
      const ajax = function () {
        axios.get("https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/mock")
          .then(data => {
            console.log("ajax返回成功");
            myData = data.data
            console.log(myData);
          })
          .catch(error => {
            console.log("ajax返回失敗");
          })
      }

我相信很多人都會通過這種鏈?zhǔn)交卣{(diào)的方式處理異步回調(diào),因為可讀性比嵌套回調(diào)要搞,但是維護的成本可能要高很多
上面的栗子,三個異步函數(shù)之間只有執(zhí)行順序上的關(guān)聯(lián),并沒有數(shù)據(jù)上的關(guān)聯(lián),但是實際開發(fā)中的情況要比這個復(fù)雜,

回調(diào)函數(shù)參數(shù)校驗

我們舉一個簡單的栗子

      let girlName = "裘千尺"

      function hr(callBack) {
        setTimeout(() => {
          girlName = "黃蓉"
          console.log("我是黃蓉");
          callBack(girlName)
        }, 0);
      }

      function gj(love) {
        console.log(`${girlName}你好,我是郭靖,認識一下吧,我喜歡${love}`);
      }
      hr(gj)

gj作為hr的回調(diào)函數(shù),并且hr將自己的一個變量傳遞給gj,gj在hr的回調(diào)中執(zhí)行,
仔細看這種寫法并不嚴(yán)謹,
如果gj并不只是一個function類型會怎么樣?
如果love的實參并不存在會怎么樣?
況且這只是一個簡單的栗子
所以回調(diào)函數(shù)中,參數(shù)的校驗是很有必要的,回調(diào)函數(shù)鏈拉的越長,校驗的條件就會越多,代碼量就會越多,隨之而來的問題就是可讀性和可維護性就會降低。

還是回調(diào)函數(shù)的校驗

但我們引用了第三方的插件或庫的時候,有時候難免要出現(xiàn)異步回調(diào)的情況,一個栗子:
xx支付,當(dāng)用戶發(fā)起支付后,我們將自己的一個回調(diào)函數(shù),傳遞給xx支付,xx支付比較耗時,執(zhí)行完之后,理論上它會去執(zhí)行我們傳遞給他的回調(diào)函數(shù),是的理論上是這樣的,我們把回調(diào)的執(zhí)行權(quán)交給了第三方,隱患隨之而來
第三方支付,多次調(diào)用我們的回調(diào)函數(shù)怎么辦?
第三方支付,不調(diào)用我們的回調(diào)函數(shù)怎么辦?
當(dāng)我們把回調(diào)函數(shù)的執(zhí)行權(quán)交給別人時,我們也要考慮各種場景可能會發(fā)生的問題

總結(jié)一下:
回調(diào)函數(shù)簡單方便,但是坑也不少,用的時候需要多注意校驗

原文鏈接

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/101162.html

相關(guān)文章

  • javascript異步與promise

    摘要:到這里,我已經(jīng)發(fā)出了一個請求買漢堡,啟動了一次交易。但是做漢堡需要時間,我不能馬上得到這個漢堡,收銀員給我一個收據(jù)來代替漢堡。到這里,收據(jù)就是一個承諾保證我最后能得到漢堡。 同期異步系列文章推薦談一談javascript異步j(luò)avascript異步中的回調(diào)javascript異步之Promise.all()、Promise.race()、Promise.finally()javascr...

    rollback 評論0 收藏0
  • 夯實基礎(chǔ)-JavaScript異步編程

    摘要:調(diào)用棧被清空,消息隊列中并無任務(wù),線程停止,事件循環(huán)結(jié)束。不確定的時間點請求返回,將設(shè)定好的回調(diào)函數(shù)放入消息隊列。調(diào)用棧執(zhí)行完畢執(zhí)行消息隊列任務(wù)。請求并發(fā)回調(diào)函數(shù)執(zhí)行順序無法確定。 異步編程 JavaScript中異步編程問題可以說是基礎(chǔ)中的重點,也是比較難理解的地方。首先要弄懂的是什么叫異步? 我們的代碼在執(zhí)行的時候是從上到下按順序執(zhí)行,一段代碼執(zhí)行了之后才會執(zhí)行下一段代碼,這種方式...

    shadowbook 評論0 收藏0
  • Javascript異步回調(diào)

    摘要:異步本質(zhì)上應(yīng)該就是多線程語言的產(chǎn)物。如果是多線程的異步,假死的應(yīng)該是運行方法的線程,而方法仍然會按預(yù)期打印出。當(dāng)然了,按我個人的理解,應(yīng)該說是是的回調(diào)函數(shù)。 引子 每個故事都有由來。前兩天在看 gulp 的時候,看到了它有個 promise 的玩意兒,然后的然后,這兩天就掉進了 javascript 的異步和回調(diào)的坑里面去了。 其間搜索了 javascript promise,看到了...

    CarlBenjamin 評論0 收藏0
  • 淺析JavaScript異步

    摘要:回調(diào)函數(shù),一般在同步情境下是最后執(zhí)行的,而在異步情境下有可能不執(zhí)行,因為事件沒有被觸發(fā)或者條件不滿足。同步方式請求異步同步請求當(dāng)請求開始發(fā)送時,瀏覽器事件線程通知主線程,讓線程發(fā)送數(shù)據(jù)請求,主線程收到 一直以來都知道JavaScript是一門單線程語言,在筆試過程中不斷的遇到一些輸出結(jié)果的問題,考量的是對異步編程掌握情況。一般被問到異步的時候腦子里第一反應(yīng)就是Ajax,setTimse...

    Tangpj 評論0 收藏0
  • JavaScript引擎是如何工作的?從調(diào)用棧到Promise你需要知道的一切

    摘要:最受歡迎的引擎是,在和中使用,用于,以及所使用的。怎么處理每個引擎都有一個基本組件,稱為調(diào)用棧。也就是說,如果有其他函數(shù)等待執(zhí)行,函數(shù)是不能離開調(diào)用棧的。每個異步函數(shù)在被送入調(diào)用棧之前必須通過回調(diào)隊列。例如方法是在中傳遞的回調(diào)函數(shù)。 ? 翻譯:瘋狂的技術(shù)宅 原文:www.valentinog.com/blog/engine… 從Call Stack,Global Me...

    zzbo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<