摘要:理解回調和原文自工程師博客,傳送門這兩個概念是編程語言的基本內容。回調地獄就是濫用回調。通常,在回調中,錯誤作為第一個參數傳遞。這個具有這兩個函數作為參數的回調稱為執行程序。到目前為止,我希望我已經讓自己了解了回調和。
理解回調和Promise
原文自工程師Fernando Hernandez博客,傳送門
這兩個概念是Javascript編程語言的基本內容。因為這種語言是在異步編程的范例下工作。
所以,我決定分享這篇文章,以便了解這兩個用來執行異步操作的特性——回調和Promise是什么。
那么,我們開始吧!
回調為了理解回調,我將做一個簡短的比喻。
假設我們正在通電話。在談話時,出現了需要立即解決的情況。我們把電話掛了,我們先做需要立即解決的事情,當我們完成時,我們再回到我們剛剛暫停的電話。
好吧,通過這個例子,我們可以大致了解什么是回調。
現在,用編程語言說。
回調是在異步操作已經完成后將要執行的功能。
回調作為參數傳遞給異步操作。通常,是作為函數的最后一個參數傳遞的。這樣做是一種很好的做法,所以請記住這一點。
回調的結構如下所示:
function sayHello() { console.log("Hello everyone"); } setTimeout(()=>{sayHello()}, 3000);
我們在上面的例子中所做的是,首先定義一個向控制臺輸出消息的函數。之后,我們使用一個名為setTimeout的計時器(此計時器是一個本機Javascript函數)。此計時器是一個異步操作,在一定時間后執行回調。在這個例子中,在3000ms(3秒)之后將執行sayHello函數。
回調模式正如我們在開始時提到的那樣,作為優秀的開發人員,我們應該將回調位置視為參數。應始終將其作為最后一個。這就是回調模式的名稱。
通過這種方式,我們的代碼將更具可讀性,并且當其他程序員處理它時將更容易維護。
我們來看另一個回調示例:
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庫,用于在我們的文件系統上進行操作。在該示例中,我們使用readFile函數來從我們的計算機中讀取文件。此函數接收兩個參數(文件路徑和回調)。我們可以注意到,名為onReadFile的回調它是最后一個參數。
匿名聲明回調是很常見的,但是如果會出現錯誤的情況,最好為它指定一個名稱,以便更容易地識別它。
最后,直到我們的代碼完成讀取所請求的文件將會執行該回調。如果存在,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)) } }) }) } })
基本上,我們可以看到,使用嵌套回調是一種不好的做法,它會在視覺上產生一種金字塔式的效果。這將成為難以維護和讀取的代碼,我們不希望這樣。
如何避免回調地獄?命名函數:正如我之前所說,你可以做的第一件事是命名你的函數(回調)。因此,當發生錯誤時,它將使用函數名稱以特定方式指示錯誤。此外,這會使你的代碼更具可讀性,當其他程序員閱讀時,它們更容易維護它。
模塊化:一旦命名了函數,就可以開始多帶帶定義它們。這樣,您將只用輸入回調名稱。首先,可以在同一文件底部定義它們。除此之外,另一種方法是將該函數寫入多帶帶的文件。這樣,我們可以在任何文件中導出和導入它。
這使得我們代碼更具有可重用性,有更高的可讀性和易維護性。
處理錯誤:編寫代碼時,我們必須記住錯誤總是會發生。為了能夠輕松地識別定位它們,編寫處理可能發生的錯誤的代碼非常重要。
通常,在回調中,錯誤作為第一個參數傳遞。我們可以通過以下方式處理錯誤:
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) }
養成良好的編程習慣,讓其余程序員不會恨你一輩子!
PromiseJavascript中的Promise就是相當于字面意思上的承諾。我們知道,當我們做出承諾時,這意味著我們將盡一切可能實現預期的結果。但是,我們也知道,由于某種原因,不能總是履行承諾。
正如承諾在現實生活中一樣,它是在Javascript中,則另一種方式表示即代碼。
讓我們看一個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的原生類(自ES6起)。
promise的構造函數接收一個參數:一個回調,它有兩個參數:
resolve
reject
這些是已經在Javascript中定義的函數,因此我們不用自己去構建它們。
這個具有這兩個函數作為參數的回調稱為執行程序。
執行者在創建承諾時立即運行。
執行函數將執行什么?好吧,在這里面,我們將放置所有必要的代碼來實現我們的承諾。
一旦執行程序完成執行,我們將發送其中一個函數作為參數。
如果實現了,我們使用resolve函數。
如果由于某種原因失敗,我們使用reject函數。
函數resolve和reject,只接收一個參數。reject函數通常會使用Error類傳遞錯誤,正如我們在前面的示例中所看到的那樣。
Promise有三個獨特的狀態:
Pending:異步操作尚未完成。
Fulfilled:異步操作已完成并返回一個值。
Rejected:指示異步操作失敗以及失敗的原因。
Promise對象有兩個屬性:
State:表示Promise的狀態。
Result:存儲Promise的值(如果已滿足)或錯誤(如果已拒絕)。
最初,Promise的狀態為“pending”,結果為“undefined”。
一旦promise完成執行,promise的狀態和結果將被修改為相應的值。取決于promise是否已完成或被拒絕。
讓我們看看下面的圖表來更好地理解它:
一旦promise改變了他們的狀態,他們就無法逆轉。
如何使用或調用Promise?為了使用我們創建的Promise,我們使用then和catch函數。在代碼中,它們看起來像這樣:
promise.then(function(result) { console.log(result) }).catch(function(err) { console.log(err) })
then允許我們處理已完成或已執行狀態的promise
函數catch將允許我們處理被拒絕狀態的promise
在then函數中,我們也可以處理被拒絕的promise。為此,處理程序接收兩個參數。第一個是已完成的promise,第二個是被拒絕的promise。通過這種方式:
promise.then(function(result) { // Handling the value console.log(result) }, function(err) { // Handling the error console.log(err) })
處理程序then和catch都是異步的。
基本上,一旦Javascript執行了下面的代碼,就會執行then和catch。
例:
promise.then(function(result) { console.log(result) }).catch(function(err) { console.log(err) }) console.log("Hello world")
我們可能認為首先它會先在控制臺輸出在promise中的value或error。但是要知道它們是異步操作,我們必須記住它將花費最少的時間來執行,因此消息“Hello world”還是會首先顯示。
Promise類有一個名為all的方法,用于執行promise數組。它看起來像這樣:
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
在隨后處理程序將在控制臺輸出每個promise的結果的數組。
如果其中一個promise被reject,則該函數將被reject并出現錯誤。如下所示:
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
還有另一種類似于all的方法,但又有所不同。它是race方法。
與all函數相同,它接收一個promise數組,但它將返回先完成或拒絕的promise。我們來看一個代碼示例:
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
我們可以看到,返回給我們的值是第二個promise返回的。這是因為第一個promise是先執行的。
讓我們看一個被拒絕的promise的另一個例子:
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函數中,將要打印的是在我們聲明的第三個promise中發現的錯誤。你可以想象得到為什么。實際上,第三個promise比其他promise先執行。
因此,無論promise是否被拒絕或完成,race方法將執行第一個并忽略其他方法。
到目前為止,我希望我已經讓自己了解了回調和promise。基本上,Javascript的這兩個特性用于處理異步操作。這就是這門語言的基礎,因此它很受歡迎。
我將很快繼續關于處理異步的另一篇文章——Async-Await。
譯者總結本文是小編的第一次譯文,翻譯不到位請見諒。由于突然想重溫一下Promise,為此對Promise的知識點進行了再次溫故,看看從不同人的角度怎么去理解Promise的。上文對Promise進行了簡單的介紹并附帶一些回調的知識點,也讓我對回調有了新的見解。相信對讀者也會有所幫助,我會再接再厲的!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101823.html
摘要:直到最近,我們仍然在用簡單的回調函數來處理異步的問題。當我們只有一個異步任務的時候使用回調函數看起來還不會有什么問題。 原文地址:http://blog.getify.com/promis... 廈門旅行歸來,繼續理解Promise 在上一篇深入理解Promise五部曲:1.異步問題中,我們揭示了JS的異步事件輪詢并發模型并且解釋了多任務是如何相互穿插使得它們看起來像是同時運行的。...
摘要:當引擎開始執行一個函數比如回調函數時,它就會把這個函數執行完,也就是說只有執行完這段代碼才會繼續執行后面的代碼。當條件允許時,回調函數就會被運行。現在,返回去執行注冊的那個回調函數。 原文地址:http://blog.getify.com/promis... 在微博上看到有人分享LabJS作者寫的關于Promise的博客,看了下覺得寫得很好,分五個部分講解了Promise的來龍去脈。從...
摘要:回調方式將回調函數作為參數傳遞給主函數,同時在主函數內部處理錯誤信息。模塊是促進中對象之間交流的模塊,它是異步事件驅動機制的核心。在異步函數的回調中,根據執行情況觸發或者事件。比如,當異常事件觸發關閉數據庫的動作時。 原文鏈接:Understanding Nodejs Event-driven Architecture 作者:Samer Buna 翻譯:野草 本文首發于前端早讀課【...
摘要:事件驅動機制的最簡單形式,是在中十分流行的回調函數,例如。在回調函數這種形式中,事件每被觸發一次,回調就會被觸發一次。回調函數需要作為宿主函數的一個參數進行傳遞多個宿主回調進行嵌套就形成了回調地獄,而且錯誤和成功都只能在其中進行處理。 學習 Node.js 一定要理解的內容之一,文中主要涉及到了 EventEmitter 的使用和一些異步情況的處理,比較偏基礎,值得一讀。 閱讀原文 大...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
閱讀 787·2021-11-12 10:36
閱讀 3363·2021-09-08 10:44
閱讀 2739·2019-08-30 11:08
閱讀 1393·2019-08-29 16:12
閱讀 2668·2019-08-29 12:24
閱讀 889·2019-08-26 10:14
閱讀 676·2019-08-23 18:32
閱讀 1160·2019-08-23 17:52