成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

【譯】理解回調(diào)和Promise

liuyix / 2609人閱讀

摘要:理解回調(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ǔ)言是在異步編程的范例下工作。

所以,我決定分享這篇文章,以便了解這兩個(gè)用來(lái)執(zhí)行異步操作的特性——回調(diào)和Promise是什么。

那么,我們開(kāi)始吧!

回調(diào)

為了理解回調(diào),我將做一個(gè)簡(jiǎn)短的比喻。

假設(shè)我們正在通電話(huà)。在談話(huà)時(shí),出現(xiàn)了需要立即解決的情況。我們把電話(huà)掛了,我們先做需要立即解決的事情,當(dāng)我們完成時(shí),我們?cè)倩氐轿覀儎倓倳和5碾娫?huà)。

好吧,通過(guò)這個(gè)例子,我們可以大致了解什么是回調(diào)。

現(xiàn)在,用編程語(yǔ)言說(shuō)。

回調(diào)是在異步操作已經(jīng)完成后將要執(zhí)行的功能。

回調(diào)作為參數(shù)傳遞給異步操作。通常,是作為函數(shù)的最后一個(gè)參數(shù)傳遞的。這樣做是一種很好的做法,所以請(qǐng)記住這一點(diǎn)。

回調(diào)的結(jié)構(gòu)如下所示:

function sayHello() {
    console.log("Hello everyone");
}

setTimeout(()=>{sayHello()}, 3000);

我們?cè)谏厦娴睦又兴龅氖?,首先定義一個(gè)向控制臺(tái)輸出消息的函數(shù)。之后,我們使用一個(gè)名為setTimeout的計(jì)時(shí)器(此計(jì)時(shí)器是一個(gè)本機(jī)Javascript函數(shù))。此計(jì)時(shí)器是一個(gè)異步操作,在一定時(shí)間后執(zhí)行回調(diào)。在這個(gè)例子中,在3000ms(3秒)之后將執(zhí)行sayHello函數(shù)。

回調(diào)模式

正如我們?cè)陂_(kāi)始時(shí)提到的那樣,作為優(yōu)秀的開(kāi)發(fā)人員,我們應(yīng)該將回調(diào)位置視為參數(shù)。應(yīng)始終將其作為最后一個(gè)。這就是回調(diào)模式的名稱(chēng)。

通過(guò)這種方式,我們的代碼將更具可讀性,并且當(dāng)其他程序員處理它時(shí)將更容易維護(hù)。

我們來(lái)看另一個(gè)回調(diào)示例:

const fs = require("fs") // Importing Nodejs library

// Declaring file path
const filePath = "./users.json"

// Asynchronous operation to read the file
fs.readFile(filePath, function onReadFile(err, result) {
    // In case of error print it in the console
    if (err) {
        console.log("There was an error: " + err)
        return // Get out of the function
    }
    // Print on the console the file and the content of it.
    console.log("The file was successfully read it: " + result)
})

在這里,我們使用Nodejs庫(kù),用于在我們的文件系統(tǒng)上進(jìn)行操作。在該示例中,我們使用readFile函數(shù)來(lái)從我們的計(jì)算機(jī)中讀取文件。此函數(shù)接收兩個(gè)參數(shù)(文件路徑和回調(diào))。我們可以注意到,名為onReadFile的回調(diào)它是最后一個(gè)參數(shù)。

匿名聲明回調(diào)是很常見(jiàn)的,但是如果會(huì)出現(xiàn)錯(cuò)誤的情況,最好為它指定一個(gè)名稱(chēng),以便更容易地識(shí)別它。

最后,直到我們的代碼完成讀取所請(qǐng)求的文件將會(huì)執(zhí)行該回調(diào)。如果存在,Javascript將在此過(guò)程中繼續(xù)執(zhí)行代碼。

回調(diào)地獄

一旦你知道回調(diào)函數(shù)是如何工作的,并付諸實(shí)踐,我們就必須記住一些東西。作為一名優(yōu)秀的開(kāi)發(fā)人員,我們必須知道如何使用它,并避免像回調(diào)地獄這樣糟糕的事情。

回調(diào)地獄就是濫用回調(diào)。 它看起來(lái)像這樣:

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

基本上,我們可以看到,使用嵌套回調(diào)是一種不好的做法,它會(huì)在視覺(jué)上產(chǎn)生一種金字塔式的效果。這將成為難以維護(hù)和讀取的代碼,我們不希望這樣。

如何避免回調(diào)地獄?

命名函數(shù):正如我之前所說(shuō),你可以做的第一件事是命名你的函數(shù)(回調(diào))。因此,當(dāng)發(fā)生錯(cuò)誤時(shí),它將使用函數(shù)名稱(chēng)以特定方式指示錯(cuò)誤。此外,這會(huì)使你的代碼更具可讀性,當(dāng)其他程序員閱讀時(shí),它們更容易維護(hù)它。

模塊化:一旦命名了函數(shù),就可以開(kāi)始多帶帶定義它們。這樣,您將只用輸入回調(diào)名稱(chēng)。首先,可以在同一文件底部定義它們。除此之外,另一種方法是將該函數(shù)寫(xiě)入多帶帶的文件。這樣,我們可以在任何文件中導(dǎo)出和導(dǎo)入它。

這使得我們代碼更具有可重用性,有更高的可讀性和易維護(hù)性。

處理錯(cuò)誤:編寫(xiě)代碼時(shí),我們必須記住錯(cuò)誤總是會(huì)發(fā)生。為了能夠輕松地識(shí)別定位它們,編寫(xiě)處理可能發(fā)生的錯(cuò)誤的代碼非常重要。

通常,在回調(diào)中,錯(cuò)誤作為第一個(gè)參數(shù)傳遞。我們可以通過(guò)以下方式處理錯(cuò)誤:

const fs = require("fs")

const filePath = "./users.json"

fs.readFile(filePath, handleFile)

function handleFile(err, result) {
    if (err) {
        return console.log("There was an error: " + err)
    }
    console.log("File: " + result)
}

養(yǎng)成良好的編程習(xí)慣,讓其余程序員不會(huì)恨你一輩子!

Promise

Javascript中的Promise就是相當(dāng)于字面意思上的承諾。我們知道,當(dāng)我們做出承諾時(shí),這意味著我們將盡一切可能實(shí)現(xiàn)預(yù)期的結(jié)果。但是,我們也知道,由于某種原因,不能總是履行承諾。

正如承諾在現(xiàn)實(shí)生活中一樣,它是在Javascript中,則另一種方式表示即代碼。

讓我們看一個(gè)Promise的例子:

let promise = new Promise(function(resolve, reject) {
    // things to do to accomplish your promise

    if(/* everything turned out fine */) {
        resolve("Stuff worked")
    } else { // for some reason the promise doesn"t fulfilled
        reject(new Error("it broke"))
    }
})

Promise是Javascript的原生類(lèi)(自ES6起)。

promise的構(gòu)造函數(shù)接收一個(gè)參數(shù):一個(gè)回調(diào),它有兩個(gè)參數(shù):

resolve

reject

這些是已經(jīng)在Javascript中定義的函數(shù),因此我們不用自己去構(gòu)建它們。

這個(gè)具有這兩個(gè)函數(shù)作為參數(shù)的回調(diào)稱(chēng)為執(zhí)行程序。

執(zhí)行者在創(chuàng)建承諾時(shí)立即運(yùn)行。

執(zhí)行函數(shù)將執(zhí)行什么?

好吧,在這里面,我們將放置所有必要的代碼來(lái)實(shí)現(xiàn)我們的承諾。

一旦執(zhí)行程序完成執(zhí)行,我們將發(fā)送其中一個(gè)函數(shù)作為參數(shù)。

如果實(shí)現(xiàn)了,我們使用resolve函數(shù)。

如果由于某種原因失敗,我們使用reject函數(shù)。

函數(shù)resolve和reject,只接收一個(gè)參數(shù)。reject函數(shù)通常會(huì)使用Error類(lèi)傳遞錯(cuò)誤,正如我們?cè)谇懊娴氖纠兴吹降哪菢印?/p>

Promise有三個(gè)獨(dú)特的狀態(tài):

Pending:異步操作尚未完成。

Fulfilled:異步操作已完成并返回一個(gè)值。

Rejected:指示異步操作失敗以及失敗的原因。

Promise對(duì)象有兩個(gè)屬性:

State:表示Promise的狀態(tài)。

Result:存儲(chǔ)Promise的值(如果已滿(mǎn)足)或錯(cuò)誤(如果已拒絕)。

最初,Promise的狀態(tài)為“pending”,結(jié)果為“undefined”。

一旦promise完成執(zhí)行,promise的狀態(tài)和結(jié)果將被修改為相應(yīng)的值。取決于promise是否已完成或被拒絕。

讓我們看看下面的圖表來(lái)更好地理解它:

一旦promise改變了他們的狀態(tài),他們就無(wú)法逆轉(zhuǎn)。

如何使用或調(diào)用Promise?

為了使用我們創(chuàng)建的Promise,我們使用then和catch函數(shù)。在代碼中,它們看起來(lái)像這樣:

promise.then(function(result) {
    console.log(result)
}).catch(function(err) {
    console.log(err)
})

then允許我們處理已完成或已執(zhí)行狀態(tài)的promise

函數(shù)catch將允許我們處理被拒絕狀態(tài)的promise

在then函數(shù)中,我們也可以處理被拒絕的promise。為此,處理程序接收兩個(gè)參數(shù)。第一個(gè)是已完成的promise,第二個(gè)是被拒絕的promise。通過(guò)這種方式:

promise.then(function(result) { // Handling the value
    console.log(result)
}, function(err) { // Handling the error
    console.log(err)
})

處理程序then和catch都是異步的。

基本上,一旦Javascript執(zhí)行了下面的代碼,就會(huì)執(zhí)行then和catch。

例:

promise.then(function(result) {
    console.log(result)
}).catch(function(err) {
    console.log(err)
})

console.log("Hello world")

我們可能認(rèn)為首先它會(huì)先在控制臺(tái)輸出在promise中的value或error。但是要知道它們是異步操作,我們必須記住它將花費(fèi)最少的時(shí)間來(lái)執(zhí)行,因此消息“Hello world”還是會(huì)首先顯示。
Promise類(lèi)有一個(gè)名為all的方法,用于執(zhí)行promise數(shù)組。它看起來(lái)像這樣:

Promise.all([
    new Promise.((resolve, reject) => setTimeout(() => resolve(1), 3000)), // 1
    new Promise.((resolve, reject) => setTimeout(() => resolve(2), 2000)), // 2
    new Promise.((resolve, reject) => setTimeout(() => resolve(3), 1000)), // 3
]).then(result => console.log(result)) // 1, 2, 3

在隨后處理程序?qū)⒃诳刂婆_(tái)輸出每個(gè)promise的結(jié)果的數(shù)組。
如果其中一個(gè)promise被reject,則該函數(shù)將被reject并出現(xiàn)錯(cuò)誤。如下所示:

Promise.all([
    new Promise.((resolve, reject) => setTimeout(() => resolve(1), 3000)), // 1
    new Promise.((resolve, reject) => setTimeout(() => resolve(2), 2000)), // 2
    new Promise.((resolve, reject) => setTimeout(() => reject(new Error("An error has ocurred")), 1000))
]).then(result => console.log(result))
.catch(err => console.log(err)) // An error has ocurred

還有另一種類(lèi)似于all的方法,但又有所不同。它是race方法。
與all函數(shù)相同,它接收一個(gè)promise數(shù)組,但它將返回先完成或拒絕的promise。我們來(lái)看一個(gè)代碼示例:

let promise1 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("promise one")
    }, 3000) // Resolve after 3 seconds
})

let promise2 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("promise two")
    }, 1000) // Resolve after 1 seconds
})

Promise.race([
    promise1,
    promise2
]).then(result => console.log(result)) // promise two

我們可以看到,返回給我們的值是第二個(gè)promise返回的。這是因?yàn)榈谝粋€(gè)promise是先執(zhí)行的。
讓我們看一個(gè)被拒絕的promise的另一個(gè)例子:

let promise1 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("promise one")
    }, 3000) // Resolve after 3 seconds
})

let promise2 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("promise two")
    }, 2000) // Resolve after 2 seconds
})

let promise3 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        reject("promise three rejected")
    }, 1000) // Reject after 1 second
})

Promise.race([
    promise1,
    promise2,
    promise3
]).then(result => console.log(result))
.catch(err => console.log(err)) // promise three is rejected

在這段代碼race函數(shù)中,將要打印的是在我們聲明的第三個(gè)promise中發(fā)現(xiàn)的錯(cuò)誤。你可以想象得到為什么。實(shí)際上,第三個(gè)promise比其他promise先執(zhí)行。

因此,無(wú)論promise是否被拒絕或完成,race方法將執(zhí)行第一個(gè)并忽略其他方法。

到目前為止,我希望我已經(jīng)讓自己了解了回調(diào)和promise。基本上,Javascript的這兩個(gè)特性用于處理異步操作。這就是這門(mén)語(yǔ)言的基礎(chǔ),因此它很受歡迎。

我將很快繼續(xù)關(guān)于處理異步的另一篇文章——Async-Await。

譯者總結(jié)

本文是小編的第一次譯文,翻譯不到位請(qǐng)見(jiàn)諒。由于突然想重溫一下Promise,為此對(duì)Promise的知識(shí)點(diǎn)進(jìn)行了再次溫故,看看從不同人的角度怎么去理解Promise的。上文對(duì)Promise進(jìn)行了簡(jiǎn)單的介紹并附帶一些回調(diào)的知識(shí)點(diǎn),也讓我對(duì)回調(diào)有了新的見(jiàn)解。相信對(duì)讀者也會(huì)有所幫助,我會(huì)再接再厲的!

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

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

相關(guān)文章

  • [] 深入理解 Promise 五部曲:2. 控制權(quán)轉(zhuǎn)換問(wèn)題

    摘要:直到最近,我們?nèi)匀辉谟煤?jiǎn)單的回調(diào)函數(shù)來(lái)處理異步的問(wèn)題。當(dāng)我們只有一個(gè)異步任務(wù)的時(shí)候使用回調(diào)函數(shù)看起來(lái)還不會(huì)有什么問(wèn)題。 原文地址:http://blog.getify.com/promis... 廈門(mén)旅行歸來(lái),繼續(xù)理解Promise 在上一篇深入理解Promise五部曲:1.異步問(wèn)題中,我們揭示了JS的異步事件輪詢(xún)并發(fā)模型并且解釋了多任務(wù)是如何相互穿插使得它們看起來(lái)像是同時(shí)運(yùn)行的。...

    alanoddsoff 評(píng)論0 收藏0
  • [] 深入理解 Promise 五部曲:1. 異步問(wèn)題

    摘要:當(dāng)引擎開(kāi)始執(zhí)行一個(gè)函數(shù)比如回調(diào)函數(shù)時(shí),它就會(huì)把這個(gè)函數(shù)執(zhí)行完,也就是說(shuō)只有執(zhí)行完這段代碼才會(huì)繼續(xù)執(zhí)行后面的代碼。當(dāng)條件允許時(shí),回調(diào)函數(shù)就會(huì)被運(yùn)行?,F(xiàn)在,返回去執(zhí)行注冊(cè)的那個(gè)回調(diào)函數(shù)。 原文地址:http://blog.getify.com/promis... 在微博上看到有人分享LabJS作者寫(xiě)的關(guān)于Promise的博客,看了下覺(jué)得寫(xiě)得很好,分五個(gè)部分講解了Promise的來(lái)龍去脈。從...

    CHENGKANG 評(píng)論0 收藏0
  • 理解Node事件驅(qū)動(dòng)架構(gòu)

    摘要:回調(diào)方式將回調(diào)函數(shù)作為參數(shù)傳遞給主函數(shù),同時(shí)在主函數(shù)內(nèi)部處理錯(cuò)誤信息。模塊是促進(jìn)中對(duì)象之間交流的模塊,它是異步事件驅(qū)動(dòng)機(jī)制的核心。在異步函數(shù)的回調(diào)中,根據(jù)執(zhí)行情況觸發(fā)或者事件。比如,當(dāng)異常事件觸發(fā)關(guān)閉數(shù)據(jù)庫(kù)的動(dòng)作時(shí)。 原文鏈接:Understanding Nodejs Event-driven Architecture 作者:Samer Buna 翻譯:野草 本文首發(fā)于前端早讀課【...

    mrcode 評(píng)論0 收藏0
  • []理解 Node.js 事件驅(qū)動(dòng)機(jī)制

    摘要:事件驅(qū)動(dòng)機(jī)制的最簡(jiǎn)單形式,是在中十分流行的回調(diào)函數(shù),例如。在回調(diào)函數(shù)這種形式中,事件每被觸發(fā)一次,回調(diào)就會(huì)被觸發(fā)一次。回調(diào)函數(shù)需要作為宿主函數(shù)的一個(gè)參數(shù)進(jìn)行傳遞多個(gè)宿主回調(diào)進(jìn)行嵌套就形成了回調(diào)地獄,而且錯(cuò)誤和成功都只能在其中進(jìn)行處理。 學(xué)習(xí) Node.js 一定要理解的內(nèi)容之一,文中主要涉及到了 EventEmitter 的使用和一些異步情況的處理,比較偏基礎(chǔ),值得一讀。 閱讀原文 大...

    Snailclimb 評(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

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

0條評(píng)論

liuyix

|高級(jí)講師

TA的文章

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