亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

Node.js中的事件驅動編程詳解

2019-11-20 14:15:56
字體:
來源:轉載
供稿:網友

在傳統程編程模里,I/O操作就像一個普通的本地函數調用:在函數執行完之前程序被堵塞,無法繼續運行。堵塞I/O起源于早先的時間片模型,這種模型下每個進程就像一個獨立的人,目的是將每個人區分開,而且每個人在同一時刻通常只能做一件事,必須等待前面的事做完才能決定下一件事做什么。但是這種在計算機網絡和Internet上被廣泛使用的“一個用戶,一個進程”的模型伸縮性很差。管理多個進程時,會耗費很多內存,上下文切換也會占用大量資源,這些對操作系統是個很大的負擔,而且隨著進程數的遞增,會導致系統性能急劇衰減。

多線程是個替代方案,線程是一個輕量級的進程,它會和同一個進程內的其它線程共享內存,它更像傳統模型的擴展,用來并發執行多個線程,當一個線程等待I/O操作時,其它線程可以接管CPU,當I/O操作完成,前面等待的線程會被喚醒。就是說,一個運行中的線程可以被中斷,然后稍候再被恢復。此外,在一些系統下線程可以在多核CPU的不同核心下并行運行。

程序員并不知道線程會在什么具體時間運行,他們必須很小心的處理共享內存的并發訪問,因此必須使用一些同步原語來同步訪問某個數據結構,比如使用鎖或信號量,以此來強制線程以特定的行為和計劃執行。那些大量依賴線程間的共享狀態的應用程序,很容易就會出現一些隨機性很強,難以查找的奇怪問題。

還有一種方式是使用多線程協作,由你自己負責顯式的釋放CPU,并把CPU時間交給其他線程使用,因為由你親自來控制線程的執行計劃,因此減小了對同步的需求,但是也提高了程序的復雜度和出錯的機會,而且并沒有避免多線程的那些問題。

什么是事件驅動編程

事件驅動編程(Evnet-driven programming)是一種編程風格,由事件來決定程序的執行流程,事件由事件處理器(event handler)或事件回調(event callback)來處理,事件回調是當某個特定事件發生時被調用的函數,比如數據庫返回了查詢結果或者用戶單擊了一個按鈕。

回想下,在傳統的堵塞I/O編程模式里,數據庫查詢可能像這樣:

復制代碼 代碼如下:

result = query('SELECT * FROM posts WHERE id = 1');

do_something_with(result);


上面的query函數會讓當前線程或進程一直處于等待狀態,直到底層數據庫完成查詢操作并返回。

在事件驅動模型里,這個查詢會變成這樣:

復制代碼 代碼如下:

query_finished = function(result) {

        do_something_with(result);

}

query('SELECT * FROM posts WHERE id = 1', query_finished);

   首先你定義了一個叫query_finished的函數,它包含了查詢完成后要做的事。然后把這個函數當做參數傳遞給query函數,當query執行完畢會調用query_finished,而不是僅僅返回查詢結果。

當你感興趣的事件發生時會調用你定義的函數,而不是簡單的返回結果值,這種編程模型就叫事件驅動編程或異步編程。這是Node一個最明顯的特性,這種編程模型意味著當前進程在執行I/O操作時不會被阻塞,因此,多個I/O操作可以并行執行,當操作完成后相應的回調函數就會被調用。

事件驅動編程底層依賴于事件循環(event loop),事件循環基本上是事件檢測和事件處理器觸發這兩種函數不斷循環調用的一個結構。在每次循環里,事件循環機制需要檢測發生了哪些事件,當事件發生時,它找到對應的回調函數并調用它。

事件循環只是運行在進程內的一個線程,當事件發生時,事件處理器可以單獨運行并且不會被中斷,也就是說:

1.在某個特定時刻最多有一個事件回調函數運行
2.任何事件處理器運行時都不會被中斷

有了這個,開發人員就可以不再為線程同步和并發修改共享內存這些事頭疼了。

一個眾所周知的秘密:

很久以前,系統編程社區的人們就知道事件驅動編程是創建高并發服務最佳方式,因為它不用保存很多上下文,因此節省了大量內存,也沒有那么多上下文切換,又節省了大量執行時間。

慢慢的,這種理念滲透到了其他的平臺和社區,出現了一些有名的事件循環實現,比如Ruby的Event machine,Perl的AnyEvnet,以及Python的Twisted,除了這些還有很多其它的實現和語言。

用這些框架做開發,需要學習框架相關的特定知識以及框架特定的類庫,比如,使用Event Machine時,為了享受非阻塞帶來的好處,你得避免使用同步類庫,只能用Event Machine的異步類庫。如果你使用了任何阻塞類庫(比如Ruby的大多數標準庫),你的服務器就失去了最佳的伸縮性,因為事件循環依然會不斷地被阻塞,時不時地阻礙了I/O事件的處理。

Node最初就被設計成一個非阻塞I/O服務器平臺,因此一般情況下,你應該期望運行在它上面的所有代碼都是非阻塞的。因為JavaScript非常小,而且它不強制使用任何I/O模型(因為它沒有標準的I/O類庫),因此Node建立在一個很純凈的環境里,不會有什么歷史遺留問題。

Node和JavaScript如何簡化了異步應用程序

Node的作者Ryan Dahl,最初使用C來開發這個項目,但是發現維護函數調用的上下文太復雜,導致代碼復雜度很高。然后他轉用Lua,但是Lua已經有個幾個阻塞的I/O類庫,阻塞和非阻塞混在一起可能會讓開發人員很迷惑并因此阻礙了很多人構建可伸縮的應用,于是Lua也被Dahl拋棄了。最后他轉向了JavaScript,JavaScript中的閉包及第一級對象的函數,這些特性使JavaScript非常適合用作事件驅動編程。JavaScript的魔力是讓Node如此流行的一個主要原因。

什么是閉包

閉包可以理解為一個特殊的函數,但是它可以繼承并訪問它自身被定義的那個作用域里的變量。當你將一個回調函數作為參數傳遞給另外一個函數時,它稍候會被調用,神奇的是,這個回調函數被稍候調用時,它居然記住了它自身定義所在的那個上下文以及父上下文里的變量,而且還可以正常訪問它們。這個強大的特性是Node成功的核心。

下面的例子將展示在Web瀏覽器里JavaScript閉包是如何工作的。假如,你要監聽一個按鈕的單機事件,你可以這樣做:

復制代碼 代碼如下:

var clickCount = 0;

document.getElementById('myButton').onclick = function() {

        clickCount += 1;

        alert("clicked " + clickCount + " times.");

};

使用jQuery時是這樣:

復制代碼 代碼如下:

var clickCount = 0;

$('button#mybutton').click(function() {

        clickedCount ++;

        alert('Clicked ' + clickCount + ' times.');

});

JavaScript里,函數是第一類對象,就是說你可以把函數當作參數來傳遞給其他函數。上面的兩個例子,前者把一個函數賦值給另一個函數,后者把函數作為參數傳遞給另一個函數,單擊事件的處理函數(回調函數)可以訪問函數定義所在代碼塊下的每個變量,在這個例子里,它可以訪問在它父閉包內定義的clickCount變量。

clickCount變量處在全局作用域(JavaScript里最外層的作用域),它保存了用戶點擊按鈕的次數,通常在全局作用域下存儲變量是個壞習慣,因為那樣很容易跟其他代碼沖突,你應該把變量放在使用它們的本地作用域里。大多時候,只用把代碼用一個函數包裝起來,等于另外創建了閉包,這樣就可以很容易避免污染全局環境,就像這樣:

復制代碼 代碼如下:

                  (function() {

                            var clickCount = 0;

                            $('button#mybutton').click(function() {

                                     clickCount ++;

                                     alert('Clicked ' + clickCount + ' times.');

                            });

                   }());


  注意:上面代碼的第七行,定義了一個函數后立刻調用它,這是JavaScript里一個常見的設計模式:通過創建函數來創建一個新的作用域。

閉包如何幫助異步編程

在事件驅動編程模型里,先編寫事件發生后將要運行的代碼,然后把這些代碼放到一個函數里,最后把這個函數當作參數傳遞給調用者,稍后由調用者函數調用。

在JavaScript里,一個函數并不是個孤立的定義,它同時會記住自己被聲明的那個作用域的上下文,這種機制讓JavaScript的函數可以訪問函數定義所在那個上下文及父上下文里的所有變量。

當你把一個回調函數當作參數傳遞給調用者后,這個函數就會在稍后的某個時刻被調用。即使定義回調函數的那個作用域已經結束,在回調函數被調用時,它依然能夠訪問這個已結束的作用域及其父作用域里的所有變量。像最后那個例子,回調函數在jQuery的click()內部被調用,它卻依然能訪問clickCount變量。

前面展現了閉包的神奇之處,把狀態變量傳遞給一個函數就可以讓你不用維護狀態就能進行事件驅動編程,JavaScript的閉包機制會幫你維護它們。

小結

事件驅動編程是一種通過事件觸發來決定程序執行流程的編程模型。程序員為他們感興趣的事件注冊回調函數(通常被稱作事件處理器),然后系統在事件發生時調用已注冊的事件處理器。這種編程模型有很多傳統阻塞編程模型所不具備的優勢,以前要實現類似的特性,就必須使用多進程/多線程才行。

JavaScript是種強大的語言,因為它的第一類型對象的函數和閉包特性,讓它很適合事件驅動編程。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91九色单男在线观看| 亚洲а∨天堂久久精品喷水| 亚洲精品久久久久| 精品久久久精品| 日日摸夜夜添一区| 亚洲国产91精品在线观看| 久久综合伊人77777尤物| 最新亚洲国产精品| 国产精品无码专区在线观看| 国产精品高潮视频| 国产精品久久久久久久久久小说| 91久久精品国产91性色| 992tv成人免费影院| 午夜精品一区二区三区av| 国产精品久久在线观看| 精品国产一区二区三区久久久狼| www.色综合| 亚洲国产精品久久91精品| 日韩大片免费观看视频播放| 欧美成人免费小视频| 亚洲精品视频网上网址在线观看| 日韩成人av在线播放| 欧美午夜丰满在线18影院| 激情久久av一区av二区av三区| 欧美性猛交xxxx富婆| 美日韩丰满少妇在线观看| 亚洲欧洲午夜一线一品| 亚洲缚视频在线观看| 欧美一级大片在线观看| 国产在线高清精品| 中文字幕日韩有码| 欧美wwwxxxx| 性欧美xxxx| 成人免费xxxxx在线观看| 色哟哟网站入口亚洲精品| 91高清视频免费| 91国产精品91| 日韩免费av在线| 91深夜福利视频| 国产丝袜一区视频在线观看| 久久久久久亚洲精品中文字幕| 日韩中文有码在线视频| 4438全国成人免费| 欧美男插女视频| 91av在线影院| 亚洲自拍欧美另类| 亚洲国产私拍精品国模在线观看| 日av在线播放中文不卡| 日韩在线视频网站| 亚洲美女免费精品视频在线观看| 国产精品美女久久久久av超清| 国产精品电影网| 国产精品电影网| 成年无码av片在线| 亚洲性生活视频| 日韩视频免费在线| 国产精品成熟老女人| 日韩中文在线中文网在线观看| 国产欧美最新羞羞视频在线观看| 亚洲精品欧美一区二区三区| 欧美性视频在线| 国产日韩精品入口| 最好看的2019的中文字幕视频| 57pao成人永久免费视频| 精品性高朝久久久久久久| 欧美性感美女h网站在线观看免费| 成人午夜两性视频| 国产精品日韩在线观看| 亚洲欧美日韩国产精品| 欧美乱大交xxxxx另类电影| 日韩av综合中文字幕| 国产精品专区一| 欧美精品精品精品精品免费| 日韩福利伦理影院免费| 2020欧美日韩在线视频| 久久久久久久国产精品视频| 51午夜精品视频| 亚洲人成在线免费观看| 日韩欧美在线视频观看| 国产精品777| 亚洲午夜精品视频| 日韩在线不卡视频| 国产精品偷伦视频免费观看国产| 欧美日韩在线第一页| 国产在线观看一区二区三区| 成人精品视频99在线观看免费| 日韩欧美国产中文字幕| 欧美黄色小视频| 81精品国产乱码久久久久久| 欧美一级大片在线免费观看| 国内精品在线一区| 亚洲福利在线看| 第一福利永久视频精品| 国产一区二区三区丝袜| 中文字幕av一区| 国产亚洲精品久久久久久牛牛| 中文字幕亚洲第一| 国产成+人+综合+亚洲欧美丁香花| 性色av一区二区咪爱| 欧美最猛性xxxx| 日韩成人在线视频观看| 国产一区私人高清影院| 国产午夜精品一区二区三区| 欧美乱大交做爰xxxⅹ性3| 欧美极品少妇xxxxx| 97视频免费观看| 欧美一区二区大胆人体摄影专业网站| 亚洲成av人影院在线观看| 亚洲国产又黄又爽女人高潮的| 久久成人亚洲精品| 国产精品成人免费视频| 欧美香蕉大胸在线视频观看| 国产精品美女免费视频| 国产高清在线不卡| 亚洲视频在线观看| 日韩中文字幕欧美| 日韩欧美国产高清91| 在线成人免费网站| 亚洲a在线观看| 久久成人人人人精品欧| 亚洲精品wwww| 精品国产乱码久久久久久虫虫漫画| 日韩精品视频在线播放| 日韩在线视频免费观看高清中文| 精品一区二区亚洲| 成人黄色片网站| 91精品在线国产| 日韩精品在线观| 欧美激情区在线播放| 亚洲最大福利视频网站| 欧美成人精品一区二区三区| 热门国产精品亚洲第一区在线| 久久国产天堂福利天堂| 欧洲美女免费图片一区| 日韩欧美国产一区二区| 亚洲一区国产精品| 奇米4444一区二区三区| 2019中文字幕免费视频| 日本欧美一级片| 美女视频黄免费的亚洲男人天堂| 在线观看视频亚洲| 91精品久久久久久久久不口人| 久久偷看各类女兵18女厕嘘嘘| 国产成人aa精品一区在线播放| 国产精品久久久久久久久借妻| 亚洲欧美综合精品久久成人| 91人人爽人人爽人人精88v| 91夜夜未满十八勿入爽爽影院| 欧美一级淫片丝袜脚交| 国产成人精品一区二区三区| 91高清免费在线观看| 欧美另类在线观看| 欧美精品免费在线| 久久噜噜噜精品国产亚洲综合| 亚洲成年人在线| 精品国产区一区二区三区在线观看| 国产精品成人播放| 在线播放精品一区二区三区| 国产精品女人久久久久久| 亚洲欧美制服综合另类| 国产精品视频一区二区三区四| 亚洲精品在线看| 一本一道久久a久久精品逆3p| 国产精品美女久久久久av超清|