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

資訊專(zhuān)欄INFORMATION COLUMN

【翻譯】關(guān)于回調(diào)地獄

Betta / 810人閱讀

摘要:回調(diào)地獄異步程序書(shū)寫(xiě)指南什么是回調(diào)地獄我們很難一眼就看懂異步,或者是使用回調(diào)函數(shù)的程序。通?;卣{(diào)函數(shù)會(huì)用在下載文件讀取文件或者數(shù)據(jù)庫(kù)相關(guān)事務(wù)等。注意還沒(méi)有被調(diào)用,它只是被創(chuàng)建然后最為回調(diào)函數(shù)傳入。

回調(diào)地獄

JavaScript異步程序書(shū)寫(xiě)指南

什么是“回調(diào)地獄”?

我們很難一眼就看懂異步JavaScript,或者是使用回調(diào)函數(shù)的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))
        }
      })
    })
  }
})

這個(gè)一堆以})結(jié)尾的金字塔,我們很親切地稱(chēng)它為——“回調(diào)地獄”。

之所以會(huì)出現(xiàn)回調(diào)地獄,是因?yàn)槲覀儗?xiě)JavaScript一般是視覺(jué)上的從上到下書(shū)寫(xiě)。很多人犯了這個(gè)錯(cuò)誤!在例如C、Ruby或者Python等其他語(yǔ)言,在第二行代碼運(yùn)行之前,第一行代碼肯定已經(jīng)運(yùn)行完了。然而如后面所說(shuō)的,JavaScript是不同的。

什么是回調(diào)函數(shù)?

回調(diào)函數(shù)是JavaScript里約定俗成的一個(gè)名稱(chēng)。實(shí)際上并不存在確定的“回調(diào)函數(shù)”,只是大家就管那個(gè)位置的函數(shù)作回調(diào)函數(shù)。與大多數(shù)運(yùn)行后立刻給出結(jié)果的函數(shù)不同,使用回調(diào)的函數(shù)要花一些時(shí)間才能得出結(jié)果?!爱惒健边@個(gè)詞就是代表‘要花時(shí)間,將來(lái)運(yùn)行’。通?;卣{(diào)函數(shù)會(huì)用在下載文件、讀取文件、或者數(shù)據(jù)庫(kù)相關(guān)事務(wù)等。

當(dāng)你調(diào)用一個(gè)普通函數(shù),你可以立刻得到它的值:

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

而使用回調(diào)的函數(shù)不能立刻得到反饋。

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

這個(gè)時(shí)候,這張gif可能要下載很久,你總不能讓程序什么都不干停下來(lái)就等它下載完。

相反,你可以?xún)?chǔ)存下載完后觸發(fā)的代碼到一個(gè)函數(shù)里,這就是回調(diào)函數(shù)!把這些代碼寫(xiě)進(jìn)downloadPhoto函數(shù),下載成功后,會(huì)運(yùn)行回調(diào)函數(shù)。

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")

我們理解回調(diào)最難的地方就是理解程序的運(yùn)行順序。例子中發(fā)生了三個(gè)主要事件,首先是handlePhoto函數(shù)被聲明,然后作為回調(diào)函數(shù)被downloadPhoto函數(shù)調(diào)用,最后控制臺(tái)打印出"Download started"。

注意handlePhoto還沒(méi)有被調(diào)用,它只是被創(chuàng)建然后最為回調(diào)函數(shù)傳入downloadPhoto。直到downloadPhoto完成下載,他都不會(huì)運(yùn)行。

這個(gè)例子說(shuō)明兩個(gè)問(wèn)題:

handlePhoto(回調(diào)函數(shù))只是儲(chǔ)存了將要運(yùn)行的東西

不要從上到下閱讀程序,程序會(huì)根據(jù)事情完成而跳轉(zhuǎn)

怎么修復(fù)回調(diào)地獄?

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

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
  })
}

這段代碼有兩個(gè)匿名函數(shù),我們來(lái)賦予他們一個(gè)函數(shù)名!

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
  })
}

你們看,給函數(shù)命名很簡(jiǎn)單,但是好處可不少:

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

在控制臺(tái)調(diào)試出錯(cuò)的時(shí)候,控制臺(tái)會(huì)告訴你是哪個(gè)函數(shù)出錯(cuò)了,而不是一個(gè)匿名函數(shù)(anonymous)

可以讓你把這些函數(shù)移動(dòng)到合適的位置,使用的時(shí)候用函數(shù)名調(diào)用就可以了

現(xiàn)在我們都寫(xiě)到程序最外層:

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
}

注意,函數(shù)聲明在底部,卻仍然能調(diào)用,這得益于函數(shù)提升。

2.模塊化

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

創(chuàng)建一個(gè)包含前面兩個(gè)函數(shù)的新文件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來(lái)自node.js的模塊系統(tǒng),可以使用在node、Electron,瀏覽器上(借助browserify)。我十分喜歡這種風(fēng)格,因?yàn)槟膬憾寄苡?,而且易于理解,不用依?lài)于其他復(fù)雜設(shè)置。

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

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

現(xiàn)在我們的代碼只有兩行,有以下好處:

易于新開(kāi)發(fā)者理解,他們不會(huì)為讀取所有的formuploader函數(shù)而陷入困境。

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

3.處理每一個(gè)錯(cuò)誤

常見(jiàn)錯(cuò)誤有幾種

語(yǔ)法錯(cuò)誤(運(yùn)行失?。?/p>

運(yùn)行時(shí)錯(cuò)誤(可以運(yùn)行但是有bug)

平臺(tái)錯(cuò)誤(文件權(quán)限問(wèn)題、磁盤(pán)問(wèn)題、網(wǎng)絡(luò)問(wèn)題)

前兩條規(guī)則主要是提高你的代碼的可讀性,而這條是讓你的代碼更穩(wěn)定。在處理回調(diào)時(shí),您將根據(jù)定義處理發(fā)送的任務(wù),在后臺(tái)執(zhí)行某些操作,最后成功完成或失敗中止。任何有經(jīng)驗(yàn)的開(kāi)發(fā)人員都會(huì)告訴你,你永遠(yuǎn)不會(huì)知道這些錯(cuò)誤發(fā)生什么時(shí)候發(fā)生,所以在問(wèn)題出現(xiàn)時(shí)都必須有所對(duì)策。

最常用的回調(diào)錯(cuò)誤處理是Node.js風(fēng)格,也就是回調(diào)函數(shù)的第一個(gè)參數(shù)總是錯(cuò)誤參數(shù)。

 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
 }

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

總結(jié)

不要嵌套函數(shù),命名后調(diào)用更好

使用函數(shù)提升

處理回調(diào)函數(shù)的每一個(gè)錯(cuò)誤

創(chuàng)建可重用函數(shù),寫(xiě)成模塊,讓你更容易讀懂代碼。把你的代碼拆分成小塊可以幫助你處理錯(cuò)誤,寫(xiě)測(cè)試,重構(gòu),方便為你的代碼寫(xiě)更穩(wěn)定的API

避免回調(diào)地獄的最重要的是移動(dòng)函數(shù),以便程序流程可以更容易地被理解,其他程序員可以不翻遍整個(gè)文件就能知道這段程序的功能。

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

一些寫(xiě)模塊的經(jīng)驗(yàn):

先把經(jīng)常重復(fù)使用的功能寫(xiě)成一個(gè)函數(shù)

當(dāng)這個(gè)函數(shù)寫(xiě)得夠大之后,把他移動(dòng)到另一個(gè)文件,用module.exports暴露它,然后用require引入

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

一個(gè)好模塊,體積要小,而且針對(duì)只一個(gè)問(wèn)題

模塊中的單個(gè)文件不應(yīng)超過(guò)約150行

模塊不應(yīng)該有多個(gè)級(jí)別的嵌套文件夾,其中包含JavaScript文件。如果是這樣,它可能做的太多了

讓有經(jīng)驗(yàn)的程序員介紹你一些好用的模塊,嘗試?yán)斫膺@個(gè)模塊的功能,如果花了幾分鐘的話,這個(gè)模塊可能就不夠好了

關(guān)于promise/生成器/ES6?

在查看更高級(jí)的解決方案之前,請(qǐng)記住,回調(diào)是JavaScript的一個(gè)基本部分(因?yàn)樗鼈冎皇呛瘮?shù)),你應(yīng)該學(xué)習(xí)如何讀寫(xiě)它們,然后再轉(zhuǎn)向更高級(jí)的語(yǔ)言功能,因?yàn)樗鼈円蕾?lài)于對(duì)回調(diào)的理解。如果您還不能寫(xiě)可維護(hù)的回調(diào)代碼,請(qǐng)繼續(xù)努力學(xué)習(xí)!

如果你真的想你的異步代碼可以“從上至下閱讀”,你可以試試這些美妙的方法。注意,這些功能在不同平臺(tái)會(huì)有兼容性問(wèn)題,使用前請(qǐng)先調(diào)查清楚!

Promise就是一種讓你從上至下寫(xiě)回調(diào)函數(shù)的方法,它鼓勵(lì)你使用try/catch處理更多類(lèi)型的錯(cuò)誤。

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

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

就我個(gè)人而言,我使用回調(diào)函數(shù)處理90%的異步代碼,當(dāng)事情變得復(fù)雜時(shí),依靠一些庫(kù),例如run-parallel或者run-series。我不認(rèn)為研究回調(diào) vs promise vs 其他什么方法對(duì)我來(lái)說(shuō)有什么幫助,最重要的還是保持代碼簡(jiǎn)單,不嵌套,并分成小模塊。

無(wú)論你選擇何種方法,請(qǐng)始終處理每個(gè)錯(cuò)誤,并保持代碼簡(jiǎn)潔。

記住,只有可以防止回調(diào)地獄和森林火災(zāi)。

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

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/83290.html

相關(guān)文章

  • ES6-7

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

    mudiyouyou 評(píng)論0 收藏0
  • 精讀《async/await 是把雙刃劍》

    摘要:本周精讀內(nèi)容是逃離地獄。精讀仔細(xì)思考為什么會(huì)被濫用,筆者認(rèn)為是它的功能比較反直覺(jué)導(dǎo)致的。同時(shí),筆者認(rèn)為,也不要過(guò)渡利用新特性修復(fù)新特性帶來(lái)的問(wèn)題,這樣反而導(dǎo)致代碼可讀性下降。 本周精讀內(nèi)容是 《逃離 async/await 地獄》。 1 引言 終于,async/await 也被吐槽了。Aditya Agarwal 認(rèn)為 async/await 語(yǔ)法讓我們陷入了新的麻煩之中。 其實(shí),筆者...

    2shou 評(píng)論0 收藏0
  • JavaScript 異步

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

    tuniutech 評(píng)論0 收藏0
  • 【譯】理解回調(diào)和Promise

    摘要:理解回調(diào)和原文自工程師博客,傳送門(mén)這兩個(gè)概念是編程語(yǔ)言的基本內(nèi)容?;卣{(diào)地獄就是濫用回調(diào)。通常,在回調(diào)中,錯(cuò)誤作為第一個(gè)參數(shù)傳遞。這個(gè)具有這兩個(gè)函數(shù)作為參數(shù)的回調(diào)稱(chēng)為執(zhí)行程序。到目前為止,我希望我已經(jīng)讓自己了解了回調(diào)和。 理解回調(diào)和Promise 原文自工程師Fernando Hernandez博客,傳送門(mén) 這兩個(gè)概念是Javascript編程語(yǔ)言的基本內(nèi)容。因?yàn)檫@種語(yǔ)言是在異步編程的...

    liuyix 評(píng)論0 收藏0
  • 10.14 百麗集團(tuán)面試經(jīng)歷

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

    bergwhite 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<