摘要:當引擎開始執行一個函數比如回調函數時,它就會把這個函數執行完,也就是說只有執行完這段代碼才會繼續執行后面的代碼。當條件允許時,回調函數就會被運行。現在,返回去執行注冊的那個回調函數。
原文地址:http://blog.getify.com/promis...
在微博上看到有人分享LabJS作者寫的關于Promise的博客,看了下覺得寫得很好,分五個部分講解了Promise的來龍去脈。從這篇文章開始,我會陸續把五篇博客翻譯出來跟大家分享,在大牛的帶領下真正理解Promise。賣個關子,作者看待Promise的角度跟我一直以來看到的講解Promise的角度完全不一樣,不只是定留在解決回調金字塔上,至少我沒想到Promise竟然有這么重要的意義。先上第一篇。
在這篇文章中,我會解釋我們為什么需要使用一個更好的方式(比如Promise)來進行異步流程的編寫。
異步你肯定聽說過Javascript中的異步編程,但是它到底是什么呢?
比如當你發生一個Ajax請求,你通常會提供一個回調函數,這個回調函數會在請求返回的時候被調用。但是你是否思考過你的回調函數在其他代碼也需要運行的時候是如何被調用的呢?如果兩個回調函數同時都要運行會怎樣呢?JS引擎會如何處理這個問題呢?
為了理解異步到底是什么,你首先需要理解一個問題:JS引擎是單線程的。這意味著在任何環境中,只有一段JS代碼會被執行。但是什么叫一段JS代碼呢?總的來說,每個函數是一個不可分割的片段或者代碼塊。當JS引擎開始執行一個函數(比如回調函數)時,它就會把這個函數執行完,也就是說只有執行完這段代碼才會繼續執行后面的代碼。
換句話說,JS引擎就像一個主題公園中的游樂項目,這個項目每次只能一個人玩兒,人們會排成一個長長的隊。大家一個個上去玩兒,下來一個然后再上去一個。如果你要玩兒這個項目你只能在隊尾排隊等待。幸運的是,每個人都很快就下來了,所以這個隊伍移動得很快。
上面說的隊伍在技術上被叫做事件輪詢。它盡可能快的進行輪詢,如果事件隊列中有代碼需要執行,它會讓JS引擎執行這段代碼,然后移到下一個需要執行的代碼,或者等待新的代碼進來。
并發如果程序在一個時間只有一個任務在執行,這樣明顯是低效而且有限制性的。如果你點擊一個按鈕提交一個表單,然后你的鼠標就會被凍結并且你不能滾動頁面,這個情況會持續幾秒直到請求返回,這樣肯定會帶來很差的用戶體驗。
這就是為什么真實的程序會有很多任務在運行而不是就只有一個任務,但是JS引擎是怎么在單線程的環境下實現的呢?
你應該想到每個代碼塊運行只要很短的時間,通常不到1毫秒。你一眨眼的時間,JS引擎會執行上千百個這樣的代碼塊。但是并不是所有的代碼塊都是為了執行同一個任務。比如,當你點擊提交按鈕之后,你也可以點擊導航或者滾動頁面等等。每個任務都會被分為很多個原子操作,執行這些原子操作會非常快。
比如:
Task A
step1
step2
step3
step4
Task B
step1
step2
JS引擎肯定不能在執行A:1步驟的同時執行B:1。但是Task B不需要等到Task A執行完后再執行,因為引擎可以在每個獨立的原子操作之間快速的切換,可能是按下面的順序執行的:
A:1
B:1
A:2
B:2(Task B完成)
A:3
A:4(Task A完成)
所以,事實上Task A和Task B是可以"同時"運行的,通過穿插地執行它們的每個原子操作,這叫做并發,換句話說,Task A和Task B是并發的。
我們很容易就會把并發和并行弄混。在真正并行的系統中,你會有多個線程,可能一個線程執行Task A同時另一個線程執行Task B。這也意味著,A:1的運行不會阻塞B:1的運行。這就好像有主題公園中有兩個分開的游樂項目,會有兩隊人在排隊,它們互相不影響。
JS事件輪詢是一個簡單的并發模型。它只允許把每個事件添加到事件隊列的隊尾,而這個隊列是先進先出的。當條件允許時,回調函數就會被運行。
同步情況下的異步在JS中編寫異步代碼一個巧妙但是煩惱的問題是JS引擎實際執行代碼的方式跟我們看上去不大一樣。例如:
makeAjaxRequest(url,function(response){ alert("Response:" + response) ; }) ;
你會怎么描述這段代碼的流程呢?大多數開發者大概會這么說:
發送Ajax請求
等到請求完成的時候,彈出提示框
但是這跟JS引擎實際的執行情況相比還不夠準確。這個問題主要是因為我們大腦習慣同步的方式。在上面這個描述中,我們使用“等到。。。的時候”來解釋,這就也是說我們會阻塞等待Ajax請求,然后繼續執行后面的程序。
JS在步驟1和步驟2之間不會阻塞。一個更準確的描述上面這段代碼的方式是:
發送Ajax請求
注冊回調函數
繼續向下執行
在未來某個時間點,驚呼“Oh,我剛才得到一個返回!”。現在,返回去執行注冊的那個回調函數。
這兩個解釋的區別似乎沒什么大不了的,但是我們跳過第三步的思考方式是一個大問題。
源代碼是給開發者的而不是計算機的。計算機只關心1和0.有無限種程序能產生一樣的1和0序列。我們編寫源代碼為了使得我們能夠以一種有含義并且準確的方式理解代碼是干嘛的。由于我們的大腦很難處理異步,所以我們需要找出一種更加同步的方式來編寫異步代碼,隱藏具體的異步實現。
例如,如果下面這段代碼能像我們需要的那樣運行并且不會阻塞,那么它是不是更好理解了呢?
response = makeAjaxRequest(url) ; alert("Response:" + response) ;
如果我們可以像這樣編碼,那么我們就可以隱藏或者抽象makeAjaxRequest()的異步本質,不需要擔心具體細節。
換句話說,我們能使得異步代碼只出現在具體的實現上,把這些煩人的東西埋在屬于它的地方。
我們還沒有解決問題。但是至少我們知道了問題是什么:用異步的方式來表達異步的代碼是艱難的,甚至很難用我們的大腦來理解。
我們需要的只是一種以同步的代碼來盡可能隱藏具體的異步實現的方式,這樣我們的大腦更好理解。我們的目標是以同步的方式來編碼而不需要關系它的實現的同步還是異步。
在第二部分:轉換的問題中,我會著手處理“回調地獄”來解釋這些問題,我們也將看到Promises是如何搞定它的。
深入理解Promise五部曲--1.異步問題
深入理解Promise五部曲--2.轉換問題
深入理解Promise五部曲--3.可靠性問題
深入理解Promise五部曲--4.擴展性問題
深入理解Promise五部曲--5.樂高問題
最后,安利下我的個人博客,歡迎訪問:http://bin-playground.top
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78171.html
摘要:直到最近,我們仍然在用簡單的回調函數來處理異步的問題。當我們只有一個異步任務的時候使用回調函數看起來還不會有什么問題。 原文地址:http://blog.getify.com/promis... 廈門旅行歸來,繼續理解Promise 在上一篇深入理解Promise五部曲:1.異步問題中,我們揭示了JS的異步事件輪詢并發模型并且解釋了多任務是如何相互穿插使得它們看起來像是同時運行的。...
摘要:有一個和相關的更大的問題。最后,請負有責任感并且使用安全的擴展。深入理解五部曲異步問題深入理解五部曲轉換問題深入理解五部曲可靠性問題深入理解五部曲擴展性問題深入理解五部曲樂高問題最后,安利下我的個人博客,歡迎訪問 原文地址:http://blog.getify.com/promis... 現在,我希望你已經看過深入理解Promise的前三篇文章了。并且假設你已經完全理解Promises...
摘要:簡單的說,即將到來的標準指出是一個,所以作為一個,必須可以被子類化。保護還是子類化這是個問題我真的希望我能創建一個忠實的給及以下。 原文地址:http://blog.getify.com/promis... 如果你需要趕上我們關于Promise的進度,可以看看這個系列前兩篇文章深入理解Promise五部曲--1.異步問題和深入理解Promise五部曲--2.控制權轉移問題。 Promi...
摘要:一個就像一個樂高玩具。問題是不是你小時候玩兒的那個有趣,它們不是充滿想象力的打氣筒,也不是一種樂高玩具。這是對的并不是給開發者使用的,它們是給庫作者使用的。不會超過這兩種情況。第二個是根據第一個處理函數如何運行來自動變成狀態成功或者失敗。 原文地址:http://blog.getify.com/promis... 在 Part4:擴展問題 中,我討論了如何擴展和抽象Promise是多么...
摘要:只要在調用異步函數時設置一個或多個回調函數,函數就會在完成時自動調用回調函數。要解決的問題是,如何將回調方法的參數從回調方法中傳遞出來,讓它可以像同步函數的返回結果一樣,在回調函數以外的控制范圍內,可以傳遞和復用。 摘要: 我們知道 JavaScript 自從有了 Generator 之后,就有了各種基于 Generator 封裝的協程。其中 hprose 中封裝的 Promise 和...
閱讀 947·2021-09-26 09:55
閱讀 3192·2021-09-22 15:36
閱讀 2982·2021-09-04 16:48
閱讀 3142·2021-09-01 11:41
閱讀 2591·2019-08-30 13:49
閱讀 1491·2019-08-29 18:46
閱讀 3546·2019-08-29 17:28
閱讀 3425·2019-08-29 14:11