首頁 web前端 js教程 Node.js 非同步程式設計之 Callback介紹(一)_node.js

Node.js 非同步程式設計之 Callback介紹(一)_node.js

May 16, 2016 pm 04:07 PM
node.js 非同步程式設計

Node.js 基於 JavaScript 引擎 v8,是單執行緒的。 Node.js 採用了與通常 Web 上的 JavaScript 非同步程式設計的方式來處理會造成阻塞的I/O操作。在 Node.js 中讀取檔案、存取資料庫、網路請求等等都有可能是異步的。對於 Node.js 新人或從其他語言背景遷移到 Node.js 上的開發者來說,非同步程式設計是比較痛苦的一部分。本章將由淺入深為大家講解 Node.js 非同步程式設計的方方面面。從最基礎的 callback 到 thunk、Promise、co 直到 ES7 計劃的 async/await。

首先我們先從一個具體的非同步程式設計的例子說起。

取得多個 ip 所在地的天氣資訊

在 ip.json 這個檔案中,有一個陣列我們存放了若干個 ip 位址,分別來自不同的地方的不同訪客,內容如下:

複製程式碼 程式碼如下:

// ip.json
["115.29.230.208", "180.153.132.38", "74.125.235.224", "91.239.201.98", "60.28.215.115"]

希望可以每一個 ip 所在地當前的天氣。將結果輸出到 weather.json 這個檔案中各式如下:
複製程式碼 程式碼如下:

// weather.json
[
  { "ip": "115.29.230.208", "weather": "Clouds", "region": "Zhejiang" },
  { "ip": "180.153.132.38", "weather": "Clear", "region": "Shanghai" },
  { "ip": "74.125.235.224", "weather": "Rain", "region": "California" },
  { "ip": "60.28.215.115", "weather": "Clear", "region": "Tianjin" }
]

整理思路,我們分成以下幾步來完成:

1.讀取 ip 位址;
2.依據 ip 位址取得 ip 所在地的地理位置;
3.依地理位置查詢當地的天氣;
4.將結果寫入 weather.json 檔案中。

這些步驟都是非同步的(讀寫檔案可以同步,但作為範例,都用非同步)。

callback

首先我們嘗試不借助任何函式庫,試著以 Node.js API 通常提供的方式——專遞一個 callback 作為非同步回呼——來實現。我們將藉助三個基礎模組:

1.fs:從檔案 ip.json 讀取 IP 清單;把結果寫入檔案;
2.request:用來發送 HTTP 請求,根據 IP 位址取得 geo 數據,再透過 geo 數據取得天氣數據;
3.querystring:用來組裝發送請求的 url 參數。

新建一個 callback.js 文件,引入這幾個模組:

複製程式碼 程式碼如下:

// callback.js
var fs = require('fs')
var request = require('request')
var qs = require('querystring')

讀取檔案中的 IP 列表,呼叫 fs.readFile 讀取檔案內容,再透過 JSON.parse 解析 JSON 資料:

複製程式碼 程式碼如下:

...
function readIP(path, callback) {
  fs.readFile(path, function(err, data) {
    if (err) {
      callback(err)
    } else {
      try {
        data = JSON.parse(data)
        callback(null, data)
      } catch (error) {
        callback(error)
      }
    }
  })
}
...

接著就是使用 IP 來取得geo,我們使用 request 來請求一個開放的 geo 服務:

複製程式碼 程式碼如下:

...
function ip2geo(ip, callback) {
  var url = 'http://www.telize.com/geoip/' ip
  request({
    url: url,
    json: true
  }, function(err, resp, body) {
    callback(err, body)
  })
}
...

使用 geo 資料來取得 weather:

複製程式碼 程式碼如下:

...
function geo2weather(lat, lon, callback) {
  var params = {
    lat: lat,
    lon: lon,
    APPID: '9bf4d2b07c7ddeb780c5b32e636c679d'
  }
  var url = 'http://api.openweathermap.org/data/2.5/weather?' qs.stringify(params)
  request({
    url: url,
    json: true,
  }, function(err, resp, body) {
    callback(err, body)
  })
}
...

現在我們已經取得 geo、取得 weather 的接口,接下來我們還有稍微複雜的問題要處理,因為 ip 有多個,所以我們需要並行地去讀取 geo 已經並行地讀取 weather 資料:
複製程式碼 程式碼如下:

...
function ips2geos(ips, callback) {
  var geos = []
  var ip
  var remain = ips.length
  for (var i = 0; i     ip = ips[i];
    (function(ip) {
      ip2geo(ip, function(err, geo) {
        if (err) {
          callback(err)
        } else {
          geo.ip = ip
          geos.push(geo)
          remain--
        }
        if (remain == 0) {
          callback(null, geos)
        }
      })
    })(ip)
  }
}

function geos2weathers(geos, callback) {
  var weathers = []
  var geo
  var remain = geos.length
  for (var i = 0; i     geo = geos[i];
    (function(geo) {
      geo2weather(geo.latitude, geo.longitude, function(err, weather) {
        if (err) {
          callback(err)
        } else {
          weather.geo = geo
          weathers.push(weather)
          remain--
        }
        if (remain == 0) {
          callback(null, weathers)
        }
      })
    })(geo)
  }
}
...

ips2geos 和 geos2weathers 都使用了比較原始的方法,remain 來計算等待傳回的個數,remain 為 0 表示並行請求結束,將處理結果裝進一個陣列傳回。

最後就是將結果寫入 weather.json 檔案:

複製程式碼 程式碼如下:

...
function writeWeather(weathers, callback) {
  var output = []
  var weather
  for (var i = 0; i     weather = weathers[i]
    output.push({
      ip: weather.geo.ip,
      weather: weather.weather[0].main,
      region: weather.geo.region
    })
  }
  fs.writeFile('./weather.json', JSON.stringify(output, null, '  '), callback)
}
...

組合上面這些函數,我們就可以實現我們的目標:

複製程式碼 程式碼如下:

...
函數處理程序錯誤(錯誤){
  console.log('錯誤:' err)
}

readIP('./ip.json', function(err, ips) {
  如果(錯誤){
    處理程序錯誤(錯誤)
  } 其他 {
    ips2geos(ips, 函數(錯誤, geos) {
      如果(錯誤){
        處理程序錯誤(錯誤)
      } 其他 {
        geos2weathers(geos, 函數(錯誤, 天氣) {
          若(錯誤){
            處理程序錯誤(錯誤)
          } 其他 {
            writeWeather(天氣, 函數(錯誤) {
              若(錯誤){
                處理程序錯誤(錯誤)
              } 其他 {
                console.log('成功!')
              }
            })
          }
        })
      }
    })
  }
})

哈哈,你媽這句話,你可能覺得這就是 JavaScript 異步的問題,說真的,不是 JavaScript 異步的真正下面問題所在。上面程式碼我們可以這樣寫:

複製程式碼以下程式碼:

...
函數 ReadIPCallback(err, ips) {
  如果(錯誤){
    處理程序錯誤(錯誤)
  } 其他 {
    ips2geos(ips, ips2geosCallback)
  }
}

函數 ips2geosCallback(err, geos) {
  如果(錯誤){
    處理程序錯誤(錯誤)
  } 其他 {
    geos2weathers(geos, geos2weathersCallback)
  }
}

函數 geos2weathersCallback(err, 天氣) {
  如果(錯誤){
    處理程序錯誤(錯誤)
  } 其他 {
    writeWeather(天氣, writeWeatherCallback)
  }
}

函數 writeWeatherCallback(err) {
  如果(錯誤){
    處理程序錯誤(錯誤)
  } 其他 {
    console.log('成功!')
  }
}

readIP('./ip.json', ReadIPCallback)

好了,這就是我們callback.js的全部內容。運行:

複製程式碼以下程式碼:

節點回調.js

將會產生weater.json檔:
複製程式碼以下程式碼:

[
  {
    "ip": "180.153.132.38",
    "天氣": "晴",
    "地區": "上海"
  },
  {
    "ip": "91.239.201.98",
    「天氣」:「雲」
  },
  {
    "ip": "60.28.215.115",
    "天氣": "晴",
    "地區": "天津"
  },
  {
    "ip": "74.125.235.224",
    “天氣”:“雲”,
    「地區」:「加州」
  },
  {
    "ip": "115.29.230.208",
    "天氣": "晴",
    "地區": "浙江"
  }
]

那正真的問題是什麼?

當然是異步的問題啦,非同步本質上要處理三個事情:

1.非同步操作何時結束,需要通知回來,Callback 是方案;
2.非同步產生的結果需要傳遞回來,Callback 接受一個 data 參數,把資料傳回來;
3.異步如果出錯了怎麼辦? Callback 接受 一個 err 參數,把錯誤傳回來。

但有沒有發現好多重複的工作(各種 callback)?上面的這些程式碼有什麼問題麼?請大家期待本文的續篇。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何用 C++ 函數實作非同步程式設計? 如何用 C++ 函數實作非同步程式設計? Apr 27, 2024 pm 09:09 PM

摘要:C++中的非同步程式設計允許多工處理,無需等待耗時操作。使用函數指標建立指向函數的指標。回調函數在非同步操作完成時被呼叫。 boost::asio等函式庫提供非同步程式支援。實戰案例示範如何使用函數指標和boost::asio實現非同步網路請求。

PHP中如何使用ReactPHP進行非同步編程 PHP中如何使用ReactPHP進行非同步編程 Jun 27, 2023 am 09:14 AM

隨著Web應用程式變得越來越複雜,程式設計師不得不採用非同步程式來處理大量請求和I/O操作。 PHP:HypertextPreprocessor也不例外。為了滿足這項需求,ReactPHP已成為目前最受歡迎的PHP非同步程式設計框架之一。在本文中,將討論如何在PHP中使用ReactPHP進行非同步程式設計。 1.ReactPHP簡介ReactPHP是基於事件驅動編程

JavaScript函數非同步程式設計:處理複雜任務的必備技巧 JavaScript函數非同步程式設計:處理複雜任務的必備技巧 Nov 18, 2023 am 10:06 AM

JavaScript函數非同步程式設計:處理複雜任務的必備技巧引言:在現代前端開發中,處理複雜任務已經成為了必不可少的一部分。而JavaScript函數非同步程式設計技巧則是解決這些複雜任務的關鍵。本文將介紹JavaScript函數非同步程式設計的基本概念和常用的實作方法,並提供具體的程式碼範例,幫助讀者更好地理解和使用這些技巧。一、非同步程式設計的基本概念在傳統的同步程式設計中,程式碼按

如何在PHP中實現非同步訊息處理 如何在PHP中實現非同步訊息處理 Jul 10, 2023 am 08:19 AM

如何在PHP中實現非同步訊息處理引言:在現代的Web應用程式中,非同步訊息處理變得越來越重要。非同步訊息處理可以提高系統的效能和可擴展性,並改善使用者體驗。 PHP作為一種常用的伺服器端程式語言,也可以透過一些技術來實現非同步訊息處理。在本文中,我們將介紹一些PHP中實作非同步訊息處理的方法,並提供程式碼範例。使用訊息佇列訊息佇列是一種解耦系統元件的方式,它允許不同的元件在

深入理解PHP8的新特性:如何有效地使用非同步程式設計和程式碼? 深入理解PHP8的新特性:如何有效地使用非同步程式設計和程式碼? Sep 11, 2023 pm 01:52 PM

深入理解PHP8的新特性:如何有效地使用非同步程式設計和程式碼? PHP8是PHP程式語言的最新主要版本,帶來了許多令人興奮的新功能和改進。其中最突出的特性之一是對非同步程式設計的支援。非同步程式設計可讓我們在處理並發任務時提高效能和回應能力。本文將深入探討PHP8的非同步程式設計特性,並介紹如何有效率地使用它們。首先,讓我們來了解一下什麼是非同步程式設計。在傳統的同步程式設計模型中,程式碼依照線性的順

Java框架非同步程式設計中常見的問題與解決方案 Java框架非同步程式設計中常見的問題與解決方案 Jun 04, 2024 pm 05:09 PM

Java框架非同步程式設計中常見的3個問題和解決方案:回呼地獄:使用Promise或CompletableFuture以更直覺的風格管理回呼。資源競爭:使用同步原語(如鎖)保護共享資源,並考慮使用執行緒安全性集合(如ConcurrentHashMap)。未處理異常:明確處理任務中的異常,並使用異常處理框架(如CompletableFuture.exceptionally())處理異常。

golang框架如何處理並發和非同步程式設計? golang框架如何處理並發和非同步程式設計? Jun 02, 2024 pm 07:49 PM

Go框架利用Go的並發和非同步特性提供高效處理並發和非同步任務的機制:1.透過Goroutine實現並發,允許同時執行多個任務;2.透過通道實現非同步編程,在不阻塞主執行緒的情況下執行任務;3.適用於實戰場景,如並發處理HTTP請求、非同步取得資料庫資料等。

PHP 非同步程式設計的優勢與劣勢? PHP 非同步程式設計的優勢與劣勢? May 06, 2024 pm 10:00 PM

非同步程式設計在PHP的優勢包括更高的吞吐量、更低的延遲、更好的資源利用和可擴展性。其劣勢包括複雜性、調試難度和有限的庫支援。在實戰案例中,ReactPHP用於處理WebSocket連接,展示了非同步程式設計的實際應用。

See all articles