您現在的位置是:電腦技術吧?>? 編程技術 ??>??異步機制,異步處理機制??>??正文詳情

異步機制,異步處理機制

嬴問寒2019-12-08 10:42:37 人圍觀
簡介異步本文主要介紹對JavaScript編程中同步和異步機制的深入理解。不僅Ajax已經滲透到了各個角落,而且node.js的流行也使得js異步編程特別具有吸引力。可異步任務處理機制理解

這篇文章主要介紹了深入理解JavaScript編程中的同步與異步機制,不僅僅是AJAX已經深入到了各個角落,Node.js的火爆也讓JS的異步編程格外引人注目,需要的朋友可以參考下  JavaScript的優勢之一是其如何處理異步代碼。

異步代碼會被放入一個事件隊列,等到所有其他代碼執行后才進行,而不會阻塞線程。

然而,對于初學者來說,書寫異步代碼可能會比較困難。

而在這篇文章里,我將會消除你可能會有的任何困惑。

  理解異步代碼  JavaScript最基礎的異步函數是setTimeout和setInterval。

setTimeout會在一定時間后執行給定的函數。

它接受一個回調函數作為第一參數和一個毫秒時間作為第二參數。

以下是用法舉例:  ? 1 2 3 4 5 6 7 8 9 10 11 console.log( a ); setTimeout(function() { console.log( c ) }, 500 ); setTimeout(function() { console.log( d ) }, 500 ); setTimeout(function() { console.log( e ) }, 500 ); console.log( b );   正如預期,控制臺先輸出a、b,大約500毫秒后,再看到c、d、e。

我用大約是因為setTimeout事實上是不可預知的。

實際上,甚至 HTML5規范都提到了這個問題:  這個API不能保證計時會如期準確地運行。

由于CPU負載、其他任務等所導致的延遲是可以預料到的。

  有趣的是,直到在同一程序段中所有其余的代碼執行結束后,超時才會發生。

所以如果設置了超時,同時執行了需長時間運行的函數,那么在該函數執行完成之前,超時甚至都不會啟動。

實際上,異步函數,如setTimeout和setInterval,被壓入了稱之為Event Loop的隊列。

  Event Loop是一個回調函數隊列。

當異步函數執行時,回調函數會被壓入這個隊列。

JavaScript引擎直到異步函數執行完成后,才會開始處理事件循環。

這意味著JavaScript代碼不是多線程的,即使表現的行為相似。

事件循環是一個先進先出(FIFO)隊列,這說明回調是按照它們被加入隊列的順序執行的。

JavaScript被 node選做為開發語言,就是因為寫這樣的代碼多么簡單啊。

  Ajax  異步Javascript與XML(AJAX)永久性的改變了Javascript語言的狀況。

突然間,瀏覽器不再需要重新加載即可更新web頁面。

在不同的瀏覽器中實現Ajax的代碼可能漫長并且乏味;但是,幸虧有jQuery(還有其他庫)的幫助,我們能夠以很容易并且優雅的方式實現客戶端-服務器端通訊。

  我們可以使用jQuery跨瀏覽器接口$.ajax很容易地檢索數據,然而卻不能呈現幕后發生了什么。

比如:  ? 1 2 3 4 5 6 7 8 9 10 var data; $.ajax({ url: some/url/1, success: function( data ) { // But, this will! console.log( data ); } }) // Oops, this won't work... console.log( data );   較容易犯的錯誤,是在調用$.ajax之后馬上使用data,但是實際上是這樣的:  ? 1 2 3 4 5 6 7 xmlhttp.open( GET, some/ur/1, true ); xmlhttp.onreadystatechange = function( data ) { if ( xmlhttp.readyState === 4 ) { console.log( data ); } }; xmlhttp.send( null );   底層的XmlHttpRequest對象發起請求,設置回調函數用來處理XHR的readystatechnage事件。

然后執行XHR的send方法。

在XHR運行中,當其屬性readyState改變時readystatechange事件就會被觸發,只有在XHR從遠端服務器接收響應結束時回調函數才會觸發執行。

  處理異步代碼  異步編程很容易陷入我們常說的回調地獄。

因為事實上幾乎JS中的所有異步函數都用到了回調,連續執行幾個異步函數的結果就是層層嵌套的回調函數以及隨之而來的復雜代碼。

  node.js中的許多函數也是異步的。

因此如下的代碼基本上很常見:  ? 1 2 3 4 5 6 7 8 9 10 var fs = require( fs ); fs.exists( index.js, function() { fs.readFile( index.js, utf8, function( err, contents ) { contents = someFunction( contents ); // do something with contents fs.writeFile( index.js, utf8, function() { console.log( whew! Done finally... ); }); }); }); console.log( executing... );   下面的客戶端代碼也很多見:  ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 GMaps.geocode({ address: fromAddress, callback: function( results, status ) { if ( status == OK ) { fromLatLng = results[0].geometry.location; GMaps.geocode({ address: toAddress, callback: function( results, status ) { if ( status == OK ) { toLatLng = results[0].geometry.location; map.getRoutes({ origin: [ fromLatLng.lat(), fromLatLng.lng() ], destination: [ toLatLng.lat(), toLatLng.lng() ], travelMode: driving, unitSystem: imperial, callback: function( e ){ console.log( ANNNND FINALLY here's the directions... ); // do something with e } }); } } }); } } });   Nested callbacks can get really nasty, but there are several solutions to this style of coding.  嵌套的回調很容易帶來代碼中的壞味道,不過你可以用以下的幾種風格來嘗試解決這個問題  The problem isn't with the language itself; it's with the way programmers use the language Async Javascript.  沒有糟糕的語言,只有糟糕的程序猿 異步JavaSript  命名函數  清除嵌套回調的一個便捷的解決方案是簡單的避免雙層以上的嵌套。

傳遞一個命名函數給作為回調參數,而不是傳遞匿名函數:  ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 var fromLatLng, toLatLng; var routeDone = function( e ){ console.log( ANNNND FINALLY here's the directions... ); // do something with e }; var toAddressDone = function( results, status ) { if ( status == OK ) { toLatLng = results[0].geometry.location; map.getRoutes({ origin: [ fromLatLng.lat(), fromLatLng.lng() ], destination: [ toLatLng.lat(), toLatLng.lng() ], travelMode: driving, unitSystem: imperial, callback: routeDone }); } }; var fromAddressDone = function( results, status ) { if ( status == OK ) { fromLatLng = results[0].geometry.location; GMaps.geocode({ address: toAddress, callback: toAddressDone }); } }; GMaps.geocode({ address: fromAddress, callback: fromAddressDone });   此外, async.js 庫可以幫助我們處理多重Ajax requests/responses. 例如:  ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 async.parallel([ function( done ) { GMaps.geocode({ address: toAddress, callback: function( result ) { done( null, result ); } }); }, function( done ) { GMaps.geocode({ address: fromAddress, callback: function( result ) { done( null, result ); } }); } ], function( errors, results ) { getRoute( results[0], results[1] ); });   這段代碼執行兩個異步函數,每個函數都接收一個名為done的回調函數并在函數結束的時候調用它。

當兩個done回調函數結束后,parallel函數的回調函數被調用并執行或處理這兩個異步函數產生的結果或錯誤。

  Promises模型  引自 CommonJS/A:  promise表示一個操作獨立完成后返回的最終結果。

  有很多庫都包含了promise模型,其中jQuery已經有了一個可使用且很出色的promise API。

jQuery在1.5版本引入了Deferred對象,并可以在返回promise的函數中使用jQuery.Deferred的構造結果。

而返回promise的函數則用于執行某種異步操作并解決完成后的延遲。

  ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 var geocode = function( address ) { var dfd = new $.Deferred(); GMaps.geocode({ address: address, callback: function( response, status ) { return dfd.resolve( response ); } }); return dfd.promise(); }; var getRoute = function( fromLatLng, toLatLng ) { var dfd = new $.Deferred(); map.getRoutes({ origin: [ fromLatLng.lat(), fromLatLng.lng() ], destination: [ toLatLng.lat(), toLatLng.lng() ], travelMode: driving, unitSystem: imperial, callback: function( e ) { return dfd.resolve( e ); } }); return dfd.promise(); }; var doSomethingCoolWithDirections = function( route ) { // do something with route }; $.when( geocode( fromAddress ), geocode( toAddress ) ). then(function( fromLatLng, toLatLng ) { getRoute( fromLatLng, toLatLng ).then( doSomethingCoolWithDirections ); });   這允許你執行兩個異步函數后,等待它們的結果,之后再用先前兩個調用的結果來執行另外一個函數。

  promise表示一個操作獨立完成后返回的最終結果。

  在這段代碼里,geocode方法執行了兩次并返回了一個promise。

異步函數之后執行,并在其回調里調用了resolve。

然后,一旦兩次調用resolve完成,then將會執行,其接收了之前兩次調用geocode的返回結果。

結果之后被傳入getRoute,此方法也返回一個promise。

最終,當getRoute的promise解決后,doSomethingCoolWithDirections回調就執行了。

  事件  事件是另一種當異步回調完成處理后的通訊方式。

一個對象可以成為發射器并派發事件,而另外的對象則監聽這些事件。

這種類型的事件處理方式稱之為 觀察者模式 。

backbone.js 庫在withBackbone.Events中就創建了這樣的功能模塊。

  ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var SomeModel = Backbone.Model.extend({ url: /someurl }); var SomeView = Backbone.View.extend({ initialize: function() { this.model.on( reset, this.render, this ); this.model.fetch(); }, render: function( data ) { // do something with data } }); var view = new SomeView({ model: new SomeModel() });   還有其他用于發射事件的混合例子和函數庫,例如 jQuery Event Emitter , EventEmitter , monologue.js ,以及node.js內建的 EventEmitter 模塊。

  事件循環是一個回調函數的隊列。

  一個類似的派發消息的方式稱為 中介者模式 , postal.js 庫中用的即是這種方式。

在中介者模式,有一個用于所有對象監聽和派發事件的中間人。

在這種模式下,一個對象不與另外的對象產生直接聯系,從而使得對象間都互相分離。

  絕不要返回promise到一個公用的API。

這不僅關系到了API用戶對promises的使用,也使得重構更加困難。

不過,內部用途的promises和外部接口的事件的結合,卻可以讓應用更低耦合且便于測試。

  在先前的例子里面,doSomethingCoolWithDirections回調函數在兩個geocode函數完成后執行。

然后,doSomethingCoolWithDirections才會獲得從getRoute接收到的響應,再將其作為消息發送出去。

  ? 1 2 3 4 5 var doSomethingCoolWithDirections = function( route ) { postal.channel( ui ).publish( directions.done, { route: route }); };   這允許了應用的其他部分不需要直接引用產生請求的對象,就可以響應異步回調。

而在取得命令時,很可能頁面的好多區域都需要更新。

在一個典型的jQuery Ajax過程中,當接收到的命令變化時,要順利的回調可能就得做相應的調整了。

這可能會使得代碼難以維護,但通過使用消息,處理UI多個區域的更新就會簡單得多了。

  ? 1 2 3 4 5 6 7 8 var UI = function() { this.channel = postal.channel( ui ); this.channel.subscribe( directions.done, this.updateDirections ).withContext( this ); }; UI.prototype.updateDirections = function( data ) { // The route is available on data.route, now just update the UI }; app.ui = new UI();   另外一些基于中介者模式傳送消息的庫有 amplify, PubSubJS, and radio.js。

  結論  JavaScript 使得編寫異步代碼很容易. 使用 promises, 事件, 或者命名函數來避免callback hell. 為獲取更多javascript異步編程信息,請點擊Async JavaScript: Build More Responsive Apps with Less . 更多的實例托管在github上,地址NetTutsAsyncJS,趕快Clone吧 !

版權聲明:本文由 嬴問寒 整理編輯。

原標題:異步輪詢機制,js異步機制

轉載注明出處:http://www.dn9ww09s.icu/program/15232.html

文章評論

    共有條評論來說兩句吧...

    用戶名:

    驗證碼:

作者推薦

  • 策略模式,狀態模式和策略模式

    策略模式,狀態模式和策略模式 相關圖片命令模式和策略模式本文主要介紹JavaScript的策略模式編程,包括使用函數和類作為策略的情況,以及在多種環境下的策略模式。請參考我最喜歡的策略設計模式為您的朋友。我盡量多用...

  • HTTP協議是,什么是HTTP協議

    HTTP協議是,什么是HTTP協議 相關圖片http基于什么協議HTTP協議是由Tim Berners-Lee發明的,他被稱為web之父。HTTP協議完全基于文本。瀏覽器通過HTTP協議與服務器交互,默認為端口80。您還可以HTTP協議稱為...

  • 點擊按鈕跳轉,如何快速點擊頁面的按鈕

    點擊按鈕跳轉,如何快速點擊頁面的按鈕 相關圖片點擊按鈕彈出輸入框本文主要介紹jQuery實現按鈕點擊全選/取消全選單選框/復選框文本框表單驗證的相關資料。對于您的朋友,請參閱jQuery實現按鈕單擊全選/取消選擇單選框/復選點擊按...

  • php explode函數,matlab中explode函數

    php explode函數,matlab中explode函數 相關圖片matlab中explode關于PHP split string expand函數的用法,使用expand函數將字符串拆分成數組。這里有幾個例子供你參考。PHP數組和擴展函數應用程序示例供strreplace函數...

  • 此頁面需要在極速模式下顯示,極速模式怎么設置

    此頁面需要在極速模式下顯示,極速模式怎么設置 相關圖片找不到兼容性視圖設置標題:JSP頁面查詢顯示通用模式作者:Evan郵箱:Evan[[email protected]背景:1。需要在JSP中以列表模式2顯示數據庫查詢結果。在良好的J極速360切換不了兼容模式...

  • 名詞解釋,LAK名詞解釋

    名詞解釋,LAK名詞解釋 相關圖片標準預防的名詞解釋本文主要介紹Python中幾種常見的名詞解釋。這種解釋也適用于其他編程語言。本文解釋了loop、iteration、recursion、traversal等名詞病理名詞解釋...

  • excel函數實例教程,函數

    excel函數實例教程,函數 相關圖片excel函數運用教程ASP函數和ASP過程提供了一種方法來創建可用于重新編程代碼的模塊,并避免在執行特定任務時一次重寫一個塊的代碼。如果在ASP頁中沒有任何函數/程序,則當ASP頁coun...

  • 2c,8c

    2c,8c 相關圖片1c本文主要介紹C?webclient類的使用實例。本文介紹如何使用webclient下載文件,openwriter打開流,使用指定的方法將數據寫入URI并上載文件c點...

  • 解決中文亂碼問題,怎么解決中文亂碼問題

    解決中文亂碼問題,怎么解決中文亂碼問題 相關圖片文件亂碼怎么解決一、安裝網易博客網友制作的Sublimitext3優化版和Sublimitext2優化版,深度集成GBK編碼,完美解決中文亂碼問題,比官方版本更適合家庭使用環境網頁中文變成亂碼...

  • 交互開發,小程序開發交互

    交互開發,小程序開發交互 相關圖片javaweb交互系統開發教程一。基本知識:1。意圖對象包含一組信息:1。組件名稱指定要啟動的活動2。做什么動作3。數據傳輸4。第5類。附加鍵值對前端數據交互...

熱評文章

  • oracle節點,oracle怎么看所有節點

    oracle節點,oracle怎么看所有節點 相關圖片oracle遞歸查詢子節點Select trans ID from trans Inst, where connect by IsLeaf = 1 starts from trans ioracle查詢子節點...

  • 漢字編碼中不支持,漢字編碼的敘述中錯誤的是

    漢字編碼中不支持,漢字編碼的敘述中錯誤的是 相關圖片下列關于微型機中漢字編碼的敘述關于JSP/servlet中的DBCS字符編碼在Internet上有很多優秀的文章和討論。本文對它們進行了一些整理,并對ibmwebsphereapplicat漢字庫中儲存漢字的編碼是...

  • oracle數據庫基礎,oracle創建數據庫

    oracle數據庫基礎,oracle創建數據庫 相關圖片oracle數據庫怎么打開甲骨文1。(1)SQL*plus命令行工具(注意:在啟用反斜杠(/)之前必須添加空格):(2)運行命令2。連接到Oracle數據庫(1)SQL*plus連接成功orical數據庫...

  • 如何獲取地址欄參數,如何在地址欄添加參數

    如何獲取地址欄參數,如何在地址欄添加參數 相關圖片asp 加密地址欄參數ASP get address bar參數代碼====================函數名:joinchar角色:add?或者參數:strurl----URLjs獲取地址欄參數...

  • file exists,file exists 什么意思

    file exists,file exists 什么意思 相關圖片exists在本文中,我們將解釋PHP中的文件存在函數,以確定文件或目錄是否存在。我們會附上一些經典的例子,你可以參考它,如果你需要的話。描述:BooFieleI存在(Stfile.separator...

  • visibility,htmlvisibility

    visibility,htmlvisibility 相關圖片high visibility本文演示了jQuery可見性過濾器:hidden和:visibility的用法。與您分享以供參考。具體分析如下:隱藏匹配所有不可見元素。如果使用CSS的visiadvisability...

  • 電腦文件夾代碼,文件代碼

    電腦文件夾代碼,文件代碼 相關圖片文件夾刪除主要任務是獲取當前目錄的路徑,然后確定文件夾是否存在。如果不是,創建它。Define('dir'root',str'replace(','/',dirname(文件夾軟件...

  • aspmvc文件上傳,asppost文件上傳

    aspmvc文件上傳,asppost文件上傳 相關圖片asp上傳組件一、解決方案:IE7或更高版本實際上可以選擇是否發送完整的本地路徑進行文件上傳,可以在IE的Internet選項中設置,如下圖所示:1。互聯網安全選項:2。完整asp文件上傳繞...

  • php關鍵字,php定義靜態變量的關鍵字

    php關鍵字,php定義靜態變量的關鍵字 相關圖片php 多繼承本文的例子描述了PHP自動獲取關鍵字的方法。與您分享以供參考。具體實現方法如下:代碼如下:$mincipin=5;//最小詞頻為$minlen=4;//最小關鍵php超全局變量...

  • 數據庫效率比較,提高數據庫效率

    數據庫效率比較,提高數據庫效率 相關圖片為了提高數據庫的查詢效率Java服務器頁面(JSP)從服務器端促進了程序的快速開發,決定了它成為一種流行的工具。雖然僵硬的一面仍然存在,但是不管它包含多少缺點,JSP可以為Web程...

關注微信

变脸官网查询