nodejs異步非阻塞IO及實例(cs)

[node-sync is a simple library that allows you to call any asynchronous function in synchronous way.]


    nodejs的最大特點,事件驅動,異步非阻塞,有且只有一個線程。

(1)異步的初步理解

nodejs包含大量異步過程和回調函數(callback),下面的代碼實現了ls的功能。

# functions like ls command
# result <filenames of ./> <end> <filenames of ./>

fs = require 'fs'

filenames = fs.readdirSync '.'
for filename in filenames
  console.log filename

fs.readdir '.', (_err, filenames)->
  for filename in filenames
    console.log filename

console.log 'end'

可以看到,上面代碼先調用了同步的readdir函數讀取當前路徑下的filename。nodejs官方文檔中,fs一節有很多file的同步實現函數及對應非同步函數,鏈接:http://nodejs.org/api/fs.html 。異步情況下,應用程序會進行下一個函數,而不會等待回調函數結束,這就是所謂的異步非阻塞。

PS:如果我們需要使用異步函數的結果,必須在回調函數中調用

(2) 順序執行邏輯不同的異步函數

這種情況較爲多見,一般分爲兩種情況:

  • 第一個異步函數的結果是第二個(異步)函數的參數

         這種情況比較簡單,只需要層層回調就可以了,大體框架如下:

       

# 定義異步函數fun1
fun1 = (_parms, _cb)->
...
...
# 調用fun1,後面定義回調函數對fun1的數據進行處理
fun1 _parms, (_data)->
...

  • 第一個異步函數的處理結束後才能調用第二個(異步)函數
這種情況下,也是層層回調,但是回調函數本身只是調用下一個異步函數,目的只是爲了保證順序執行。比如需要處理文件,先讀取下日誌並保存,然後排序合併。然後刪除原始日誌,排序合併必須在日誌都讀取保存完成後,而刪除必須在合併完成後,這就是一種必須的順序執行,否則數據就會不準確。大體框架如下:
# 定義三個函數fun*
fun1 = (_parms1, _cb)->
...
fun2 = (_parm2, _cb)->
...
fun3 = (_parm3)->
...
...
# 調用處理,定義了兩個函數直接調用下一步的函數,並用作回調函數
_funcb2 = -> fun3 _parms3
_fun1cb = -> fun2 _parms2, _funcb2
fun1 _parms1, _fun1cb
上面的cb函數必須在fun1前定義,但執行是從fun1開始的,它執行完成再調用_fun1cb,它又會執行fun2函數,完成後調用_funcb2,這樣就滿足了上面順序執行的需求。

(3)順序執行邏輯相同異步函數

執行邏輯相同的異步函數時,上面(2)中的層層調用的方法並不優雅,但同一般寫法不同,這時nodejs使用while,break語句會報錯。此時,可以使用函數嵌套函數的方法。例子如下:

# Don't try to do this with 'while' and 'break'
# This's a example of asynchronous function nested asynchronous function

http = require "http"

# 獲取某url的數據
getdata = (_url, _callback) ->
  http.get _url, (_res)->
    _body = ""
    _res.on 'data', (_chunk) ->
      _body += _chunk
    _res.on 'end', ->
      try
        _stat = JSON.parse _body
      catch _e
        process.stderr.write _e
        process.exit 1
      if not _callback
        console.log _stat
      else
        _callback _stat
  " "

# 獲得多個url的數據
request = (_urls, _ret, _callback = null)->
  _url = _urls.shift()
  getdata _url[1], (_data)->
    _ret[_url[0]] = _data
    _callback = console.log if not _callback
    return _callback _ret if _urls.length is 0
    request _urls, _ret, _callback

module.exports = {getdata, request}

getdata是通過url獲取頁面數據的方法,當我們有一組urls時,可以調用request方法來獲取數據。

request方法中,獲取的data存在_ret中,並作爲參數傳遞給再次調用的request函數直到urls遍歷完成。


參考:http://www.ruanyifeng.com/blog/2013/10/event_loop.html  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章