Express バックエンドを作成しているときは、多くの場合、大量の非同期 IO を処理する必要があります。古代には、私たちは皆、チャンク関数を使用していました。これは、デフォルトの最初のパラメーターが error
である最もよく知られている関数です。 Mongo データベースの操作をシミュレーションして、その感触をつかんでみましょう。 error
的函数。我们来模拟一个Mongo数据库的操作,感受一下。
本文主要介绍NodeJs通过async/await处理异步的方法,内容挺不错的,现在分享给大家,也给大家做个参考,希望能帮助到大家。
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
$ npm install babel-core --save
$ npm install babel-preset-es2015 --save
$ npm install babel-preset-stage-3 --save
コールバック地獄
であり、コールバックが関数に分割されると、非常に断片化されます。皆さんに嫌な思いをさせないように、エラー処理については書きませんでした。通常、すべての非同期操作では、それに応じて error
を表示または処理する必要があります。
プロミスの時代
その後、チェーンオペレーションとも言えるプロミスのより良い時代に入りました。 Promise については、以前に一連のブログ記事を書いていますので、興味があれば読んでみてください。上記を書き換えた後の状況を見てみましょう。
// webpack.config.js // 省略上面的文件输入输出的配置,直接看模块加载器的配置 module: { loaders: [ { test: /\.js$/, exclude: /(node_modules|bower_components)/, loader: "babel", query: { presets: ['es2015', 'stage-3'] } }, ] }
ピラミッドを平らにして線形構造にしたことがわかります。気持ち悪くてメンテナンスが難しかった以前のチャンク関数に比べて、プロミス関数になり、エラー処理が非常にエレガントになりました。しかし、依然として特定の問題を無視することはできません。たとえば、特定のデータを共有するために、各関数が独自の独立したスコープを持つことを我慢する必要があります。最も重要なことは、それが私たちが慣れ親しんでいる同期プログラミングとは依然として異なるということです。
Generator時代
Master TJは、ES6のGeneratorイテレータを通じて、最も有名なco
ライブラリである非同期プログラミングの同期機能を初めて実現しました。 co(function *(){})
を使用すると、イテレータを通じて関数を内部的に制御できます。ここでは co
がランチャーとして機能します。前回のブログ投稿で、Generator とその会社について同じことを言いました。
// index.js // 用于引入babel,并且启动app.js require("babel-core/register"); require("./app.js");
co でラップされた関数内では、次のコードが引き続き実行される前に 1 つの非同期実行が完了するだけです。また、エラー処理も try and catch
を通じて実装されます。しかし、認めなければならないのは、結局のところイテレータは非同期のために存在しているわけではないということです。 yield
と *
のセマンティクスは、非同期関数フラグを表しません。そしてイテレーターは co によって駆動される必要がありますが、これは私たちが想像した関数とは少し異なります。
{ "presets": ["stage-3", "es2015"] }
inserData
は、ランチャー ドライバーを必要とせずに直接呼び出すことができる実際の関数であることがわかります。もちろん内部的には yield
の処理が await
になる以外は大きな違いがないようにも感じられます。 async/await は、非同期プログラミングのセマンティクスにより一致しています。 🎜🎜それでは、どうやってそれを使うかということです🎜🎜🎜使用してください🎜🎜🎜 最初から、babel はすでに非同期変換をサポートしていると言いました。そのため、それを使用するときに babel を導入するだけで済みます。もちろん、サーバー側とブラウザ側で処理方法が異なっていても構いません。始める前に、必要な async/await コンパイル済みファイルを含む次のパッケージを導入する必要があります。 🎜🎜🎜🎜🎜rrreee🎜🎜ブラウザ側🎜🎜🎜Babel は元々、古いブラウザが新しい ES6 機能をサポートし、開発エクスペリエンスを向上できるようにするために登場しました。そのため、Babel は最初から babel-cli ターミナルを通じてコンパイルできます。または、ブラウザ側でコンパイルするための babel ファイルを導入します。もちろん、これらは私が最も推奨するものではないので、省略します。フロントエンドの静的リソース構成では、webpack が静的リソースのモジュール依存関係、パッケージ化とマージ、言語の前処理をサポートするようになりました。もちろん、ここでは Babel 処理を参照します。 🎜🎜🎜🎜🎜rrreee🎜それでは楽しく使えます。 🎜🎜🎜サーバー側🎜🎜🎜相対的に言えば、バックエンドはフロントエンドよりもはるかに多くの非同期IOを処理する必要があり、これもより必要です。では、サーバー側に babel を導入するにはどうすればよいでしょうか? 🎜🎜実際、最も簡単で最も面倒な方法は、babel を介して js ファイルを直接コンパイルして新しいファイルを作成し、それを使用することです。もちろん、冗長なファイルが存在することは避けられません。別の方法を試してみましょう。 🎜🎜公式に提供されている require フックメソッドを使用します。その名前が示すように、require を介して受信した後、次のファイルは必要に応じて Babel によって処理されます。 CommonJs は同期モジュールの依存関係であることがわかっているため、これも実行可能な方法です。起動用の js ファイルがもう 1 つ必要です。これは実際にプログラムを実行する js ファイルです。 🎜🎜🎜🎜🎜// index.js // 用于引入babel,并且启动app.js require("babel-core/register"); require("./app.js");
配置完hook之后,我们就配置babel的.babelrc文件,它是一个json格式的文件。es2015看情况配置,如果是已经是Node5.0版本,就无需再进行编译。
{ "presets": ["stage-3", "es2015"] }
最后我们的异步函数代码,写在app.js里即可。
相关推荐:
以jQuery中$.Deferred对象为例讲解promise对象是如何处理异步问题_jquery
以上がNodeJs は async と await を通じて非同期メソッドを処理しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。