国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

NodeJs通過async/await處理異步的方法

2019-11-19 15:12:58
字體:
來源:轉載
供稿:網友

場景

遠古時代

我們在編寫express后臺,經常要有許多異步IO的處理。在遠古時代,我們都是用chunk函數處理,也就是我們最熟悉的那種默認第一個參數是error的函數。我們來模擬一個Mongo數據庫的操作,感受一下。

mongoDb.open(function(err, db){  if(!err){    db.collection("users", function(err, collection){      if(!err){        let person = {name: "yika", age: 20};        collection.insert(person, function(err, result){          if(!err){            console.log(result);          }        });      }    })  }});

這個也就是被我們所詬病的callback hell,一堆橫向金字塔,如果將回調拆分成函數,則會變得非常支離破碎。為了防止到惡心到大家,我甚至沒有寫關于錯誤的處理,正常來說,每一個異步的操作都需要都它的error進行相應的顯示或處理的。

Promise時代

后來進入了好一點的時代就是Promise,我們也可以稱作鏈式操作。關于Promise,我也是之前有專門寫過一系列的博文,有興趣可以回頭翻一下。這里來看看,將以上改寫之后的狀況。

let person = {name: "yika"};mongoDb  .open()  .then(function(database){   return database.collection("users");  })  .then(function(collection){   return collection.insert(person);  })  .then(function(result){   console.log(result);  })  .catch(function(e){   throw new Error(e);  })

我們可以看到,我們將金字塔已經平鋪成一條線狀結構了。相比之前惡心難以維護的chunk函數,變成了promise函數,并且錯誤的處理也變得十分優雅。但是我們仍然不可忽視某些問題,例如我們必須忍受各個邏輯被一個又一個的then()包裹起來,每一個函數都有其獨立的作用域,如果為了共享某個數據就必須掛在最外層,最重要的還是,它與我們熟悉的同步編程仍然有差別。

Generator時代

TJ大神,借著ES6的Generator迭代器,最早實現了異步編程同步化的功能,也就是最為我們所熟知的co庫。我們通過co(function *(){})可以使函數內部通過迭代器來控制。而co在這里則是充當了啟動器的角色。關于Generator和co我在之前的博文也同樣說過。

let co = require("co");co(function *(){  let db, collection, result;   let person = {name: "yika"};  try{    db = yield mongoDb.open();    collection = yield db.collection("users");    result = yield collection.insert(person);  }catch(e){    console.error(e.message);  }  console.log(result);});

我們已經非常接近同步編程了,在co包裹的函數內部,只有一個異步執行完畢,才會繼續執行下面的代碼。并且錯誤的處理也是通過try and catch進行實現的。不過我們不得不承認的是,迭代器終究不是為異步而存在的。里面的yield*的語義也并不代表的就是異步函數標志。并且迭代器是需要co去驅動的,它和我們想象中的函數多少有一點點不同。

async/await時代

我們關注到ES7的async/await,才發現這才是我們想要的!我們將上面的代碼小小改寫一下。

async function insertData(person){  let db, collection, result;   try{    db = await mongoDb.open();    collection = await db.collection("users");    result = await collection.insert(person);  }catch(e){    console.error(e.message);  }  console.log(result);} insertData({name: "yika"});

我們可以看到inserData是一個真正的函數,是我們可以直接去調用而無需啟動器驅動的。當然內部我們也可以感受到處理yield變成了await以外,并沒有很大區別。async/await,更符合我們異步編程的語義。

那么問題來了,how to use it?

使用

我們一開始就說過,babel已經支持async的transform了,所以我們使用的時候引入babel就行。當然server端和browser端,可以有不同的處理方法。在開始之前我們需要引入以下的package,preset-stage-3里就有我們需要的async/await的編譯文件。

$ npm install babel-core --save$ npm install babel-preset-es2015 --save$ npm install babel-preset-stage-3 --save

Browser端

Babel一開始的出現就是為了讓舊瀏覽器也能支持新的ES6特性,提升我們的開發體驗。所以在Babel一開始就是可以通過babel-cli終端進行編譯的。或者引入babel文件在瀏覽器端進行編譯。當然這些都不是我最推薦的,所以我就帶過不說啦。在前端靜態資源配置里,webpack是現在比較好的解決方案,它支持靜態資源的模塊依賴,打包合并,還有語言的預處理,當然在這里我們就是指babel的處理。

// webpack.config.js// 省略上面的文件輸入輸出的配置,直接看模塊加載器的配置module: {  loaders: [    {      test: //.js$/,      exclude: /(node_modules|bower_components)/,      loader: "babel",      query: {       presets: ['es2015', 'stage-3']      }    },  ]}

這樣我們就可以愉快的使用了。

Server端

相對來說,后端比前端需要處理的異步IO地方多得多,也是更加需要這個。那我們在Server端又如何引入babel呢?

其實最簡單也是最麻煩的方法就是,直接把js文件通過babel編譯出新的文件再來使用。當然也就免不了冗余文件了,眼不見心不煩,還是換一個方法吧。

我們使用官方提供的require hook方法,顧名思義就是通過require進來后,接下來的文件進行require的時候都會經過Babel的處理。因為我們知道CommonJs是同步的模塊依賴,所以也是可行的方法。我們需要多一個用于啟動的js文件,一個真正執行程序的js文件。

// index.js // 用于引入babel,并且啟動app.jsrequire("babel-core/register");require("./app.js");

配置完hook之后,我們就配置babel的.babelrc文件,它是一個json格式的文件。es2015看情況配置,如果是已經是Node5.0版本,就無需再進行編譯。

{ "presets": ["stage-3", "es2015"]}

最后我們的異步函數代碼,寫在app.js里即可。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 年辖:市辖区| 南川市| 乳源| 金塔县| 米泉市| 准格尔旗| 思茅市| 石河子市| 东平县| 偏关县| 桃园市| 闽侯县| 襄汾县| 安阳市| 龙口市| 怀安县| 彰化县| 诸城市| 垣曲县| 兴安县| 同仁县| 大兴区| 彩票| 古浪县| 板桥市| 呈贡县| 房产| 彝良县| 应城市| 石楼县| 海晏县| 文山县| 万荣县| 灵宝市| 称多县| 辽宁省| 岑巩县| 仲巴县| 衡南县| 禹城市| 东乌珠穆沁旗|