国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【翻譯】關于回調地獄

Betta / 803人閱讀

摘要:回調地獄異步程序書寫指南什么是回調地獄我們很難一眼就看懂異步,或者是使用回調函數的程序。通常回調函數會用在下載文件讀取文件或者數據庫相關事務等。注意還沒有被調用,它只是被創建然后最為回調函數傳入。

回調地獄

JavaScript異步程序書寫指南

什么是“回調地獄”?

我們很難一眼就看懂異步JavaScript,或者是使用回調函數的JavaScript程序。例如下面這段代碼:

fs.readdir(source, function (err, files) {
  if (err) {
    console.log("Error finding files: " + err)
  } else {
    files.forEach(function (filename, fileIndex) {
      console.log(filename)
      gm(source + filename).size(function (err, values) {
        if (err) {
          console.log("Error identifying file size: " + err)
        } else {
          console.log(filename + " : " + values)
          aspect = (values.width / values.height)
          widths.forEach(function (width, widthIndex) {
            height = Math.round(width / aspect)
            console.log("resizing " + filename + "to " + height + "x" + height)
            this.resize(width, height).write(dest + "w" + width + "_" + filename, function(err) {
              if (err) console.log("Error writing file: " + err)
            })
          }.bind(this))
        }
      })
    })
  }
})

這個一堆以})結尾的金字塔,我們很親切地稱它為——“回調地獄”。

之所以會出現回調地獄,是因為我們寫JavaScript一般是視覺上的從上到下書寫。很多人犯了這個錯誤!在例如C、Ruby或者Python等其他語言,在第二行代碼運行之前,第一行代碼肯定已經運行完了。然而如后面所說的,JavaScript是不同的。

什么是回調函數?

回調函數是JavaScript里約定俗成的一個名稱。實際上并不存在確定的“回調函數”,只是大家就管那個位置的函數作回調函數。與大多數運行后立刻給出結果的函數不同,使用回調的函數要花一些時間才能得出結果。“異步”這個詞就是代表‘要花時間,將來運行’。通常回調函數會用在下載文件、讀取文件、或者數據庫相關事務等。

當你調用一個普通函數,你可以立刻得到它的值:

var result = multiplyTwoNumbers(5, 10)
console.log(result)
// 50 gets printed out

而使用回調的函數不能立刻得到反饋。

var photo = downloadPhoto("http://coolcats.com/cat.gif")
// photo is "undefined"!

這個時候,這張gif可能要下載很久,你總不能讓程序什么都不干停下來就等它下載完。

相反,你可以儲存下載完后觸發的代碼到一個函數里,這就是回調函數!把這些代碼寫進downloadPhoto函數,下載成功后,會運行回調函數。

downloadPhoto("http://coolcats.com/cat.gif", handlePhoto)

function handlePhoto (error, photo) {
  if (error) console.error("Download error!", error)
  else console.log("Download finished", photo)
}

console.log("Download started")

我們理解回調最難的地方就是理解程序的運行順序。例子中發生了三個主要事件,首先是handlePhoto函數被聲明,然后作為回調函數被downloadPhoto函數調用,最后控制臺打印出"Download started"。

注意handlePhoto還沒有被調用,它只是被創建然后最為回調函數傳入downloadPhoto。直到downloadPhoto完成下載,他都不會運行。

這個例子說明兩個問題:

handlePhoto(回調函數)只是儲存了將要運行的東西

不要從上到下閱讀程序,程序會根據事情完成而跳轉

怎么修復回調地獄?

你只需要跟著一下三步走:

1.減少代碼嵌套

以下是一些用于AJAX的瀏覽器端代碼(使用browser-request):

var form = document.querySelector("form")
form.onsubmit = function (submitEvent) {
  var name = document.querySelector("input").value
  request({
    uri: "http://example.com/upload",
    body: name,
    method: "POST"
  }, function (err, response, body) {
    var statusMessage = document.querySelector(".status")
    if (err) return statusMessage.value = err
    statusMessage.value = body
  })
}

這段代碼有兩個匿名函數,我們來賦予他們一個函數名!

var form = document.querySelector("form")
form.onsubmit = function formSubmit (submitEvent) {
  var name = document.querySelector("input").value
  request({
    uri: "http://example.com/upload",
    body: name,
    method: "POST"
  }, function postResponse (err, response, body) {
    var statusMessage = document.querySelector(".status")
    if (err) return statusMessage.value = err
    statusMessage.value = body
  })
}

你們看,給函數命名很簡單,但是好處可不少:

有了函數名,可以很容易知道這段代碼的作用

在控制臺調試出錯的時候,控制臺會告訴你是哪個函數出錯了,而不是一個匿名函數(anonymous)

可以讓你把這些函數移動到合適的位置,使用的時候用函數名調用就可以了

現在我們都寫到程序最外層:

document.querySelector("form").onsubmit = formSubmit

function formSubmit (submitEvent) {
  var name = document.querySelector("input").value
  request({
    uri: "http://example.com/upload",
    body: name,
    method: "POST"
  }, postResponse)
}

function postResponse (err, response, body) {
  var statusMessage = document.querySelector(".status")
  if (err) return statusMessage.value = err
  statusMessage.value = body
}

注意,函數聲明在底部,卻仍然能調用,這得益于函數提升。

2.模塊化

用上面的例子,我們將把它拆分成多個文件,我會告訴你怎么把他做成模塊。

創建一個包含前面兩個函數的新文件formuploader.js

module.exports.submit = formSubmit

function formSubmit (submitEvent) {
  var name = document.querySelector("input").value
  request({
    uri: "http://example.com/upload",
    body: name,
    method: "POST"
  }, postResponse)
}

function postResponse (err, response, body) {
  var statusMessage = document.querySelector(".status")
  if (err) return statusMessage.value = err
  statusMessage.value = body
}

module.exports來自node.js的模塊系統,可以使用在node、Electron,瀏覽器上(借助browserify)。我十分喜歡這種風格,因為哪兒都能用,而且易于理解,不用依賴于其他復雜設置。

我們得到了formuploader.js,只要引入并使用它就可以了!操作如下:

var formUploader = require("formuploader")
document.querySelector("form").onsubmit = formUploader.submit

現在我們的代碼只有兩行,有以下好處:

易于新開發者理解,他們不會為讀取所有的formuploader函數而陷入困境。

formuploader不用復制粘貼代碼,只要在github或者npm下載分享的代碼就可以了。

3.處理每一個錯誤

常見錯誤有幾種

語法錯誤(運行失?。?/p>

運行時錯誤(可以運行但是有bug)

平臺錯誤(文件權限問題、磁盤問題、網絡問題)

前兩條規則主要是提高你的代碼的可讀性,而這條是讓你的代碼更穩定。在處理回調時,您將根據定義處理發送的任務,在后臺執行某些操作,最后成功完成或失敗中止。任何有經驗的開發人員都會告訴你,你永遠不會知道這些錯誤發生什么時候發生,所以在問題出現時都必須有所對策。

最常用的回調錯誤處理是Node.js風格,也就是回調函數的第一個參數總是錯誤參數。

 var fs = require("fs")

 fs.readFile("/Does/not/exist", handleFile)

 function handleFile (error, file) {
   if (error) return console.error("Uhoh, there was an error", error)
   // otherwise, continue on and use `file` in your code
 }

第一個參數是error是一個簡單的共識,這樣做可以提醒你必須處理你的錯誤。如果是第二個參數的話你很容易把代碼寫成function handleFile (file) { }然后就忘了處理錯誤。
代碼規范化工具也可以提醒你添加回調錯誤處理,最簡單的方法之一是使用standard。只是在你的文件目錄運行 $ standard就能檢查你的代碼有沒有缺少錯誤處理。

總結

不要嵌套函數,命名后調用更好

使用函數提升

處理回調函數的每一個錯誤

創建可重用函數,寫成模塊,讓你更容易讀懂代碼。把你的代碼拆分成小塊可以幫助你處理錯誤,寫測試,重構,方便為你的代碼寫更穩定的API

避免回調地獄的最重要的是移動函數,以便程序流程可以更容易地被理解,其他程序員可以不翻遍整個文件就能知道這段程序的功能。

你可以先把函數移動到底部,然后逐漸把函數寫到模塊文件里,然后使用require引入它(就像引用其他npm模塊一樣)。

一些寫模塊的經驗:

先把經常重復使用的功能寫成一個函數

當這個函數寫得夠大之后,把他移動到另一個文件,用module.exports暴露它,然后用require引入

如果你的代碼是通用的,可以寫readme文件和package.json發布到npm或者github

一個好模塊,體積要小,而且針對只一個問題

模塊中的單個文件不應超過約150行

模塊不應該有多個級別的嵌套文件夾,其中包含JavaScript文件。如果是這樣,它可能做的太多了

讓有經驗的程序員介紹你一些好用的模塊,嘗試理解這個模塊的功能,如果花了幾分鐘的話,這個模塊可能就不夠好了

關于promise/生成器/ES6?

在查看更高級的解決方案之前,請記住,回調是JavaScript的一個基本部分(因為它們只是函數),你應該學習如何讀寫它們,然后再轉向更高級的語言功能,因為它們依賴于對回調的理解。如果您還不能寫可維護的回調代碼,請繼續努力學習!

如果你真的想你的異步代碼可以“從上至下閱讀”,你可以試試這些美妙的方法。注意,這些功能在不同平臺會有兼容性問題,使用前請先調查清楚!

Promise就是一種讓你從上至下寫回調函數的方法,它鼓勵你使用try/catch處理更多類型的錯誤。

Generator可以讓你“暫?!币粋€函數(而不暫停整個程序),它也能你從上至下寫異步函數,但是代價是代碼有點復雜難以理解。wat就是使用這個方法。

Async functions是ES7的特性,是生成器和promise更高級的封裝,有興趣自己谷歌一下唄。

就我個人而言,我使用回調函數處理90%的異步代碼,當事情變得復雜時,依靠一些庫,例如run-parallel或者run-series。我不認為研究回調 vs promise vs 其他什么方法對我來說有什么幫助,最重要的還是保持代碼簡單,不嵌套,并分成小模塊。

無論你選擇何種方法,請始終處理每個錯誤,并保持代碼簡潔

記住,只有可以防止回調地獄和森林火災。

原文: http://callbackhell.com/
本文github地址: https://github.com/ssshooter/...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83290.html

相關文章

  • ES6-7

    摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...

    mudiyouyou 評論0 收藏0
  • 精讀《async/await 是把雙刃劍》

    摘要:本周精讀內容是逃離地獄。精讀仔細思考為什么會被濫用,筆者認為是它的功能比較反直覺導致的。同時,筆者認為,也不要過渡利用新特性修復新特性帶來的問題,這樣反而導致代碼可讀性下降。 本周精讀內容是 《逃離 async/await 地獄》。 1 引言 終于,async/await 也被吐槽了。Aditya Agarwal 認為 async/await 語法讓我們陷入了新的麻煩之中。 其實,筆者...

    2shou 評論0 收藏0
  • JavaScript 異步

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...

    tuniutech 評論0 收藏0
  • 【譯】理解回調和Promise

    摘要:理解回調和原文自工程師博客,傳送門這兩個概念是編程語言的基本內容。回調地獄就是濫用回調。通常,在回調中,錯誤作為第一個參數傳遞。這個具有這兩個函數作為參數的回調稱為執行程序。到目前為止,我希望我已經讓自己了解了回調和。 理解回調和Promise 原文自工程師Fernando Hernandez博客,傳送門 這兩個概念是Javascript編程語言的基本內容。因為這種語言是在異步編程的...

    liuyix 評論0 收藏0
  • 10.14 百麗集團面試經歷

    摘要:此選擇器等價于此選擇器等價于要匹配含有特定屬性但不等于特定值的元素請使用。之前看到的派上了用場。用法返回值集合元素說明匹配給定的屬性是以包含某些值的元素??梢园我猱惒讲僮?,而必須是同步函數。 一面 1. 自我介紹 2. jQuery的選擇器 jQuery的選擇器與css中的選擇器很相似,通過使用css中的選擇器來選取HTML節點 1. #id 用法: $(#myDiv);...

    bergwhite 評論0 收藏0

發表評論

0條評論

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