Express 백엔드를 작성할 때 많은 비동기 IO를 처리해야 하는 경우가 많습니다. 고대에는 우리 모두가 Chunk 함수를 사용했습니다. 이 함수는 기본 첫 번째 매개변수가 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
이것이 우리가 수평 피라미드 무리인 콜백 지옥
을 비판한 것입니다. 콜백이 함수로 분할되면 매우 조각화됩니다. 모든 사람이 혐오감을 느끼는 것을 방지하기 위해 오류 처리에 대해서는 글도 쓰지 않았습니다. 일반적으로 모든 비동기 작업은 그에 따라 오류
를 표시하거나 처리해야 합니다.
Promise Era
이후 우리는 체인 운영이라고도 할 수 있는 더 나은 Promise 시대를 맞이했습니다. 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 Iterator를 통해 가장 잘 알려진 co
라이브러리인 비동기 프로그래밍의 동기화 기능을 최초로 구현했습니다. co(function *(){})
를 사용하여 반복자를 통해 내부적으로 함수를 제어할 수 있습니다. 그리고 여기서는 co
가 런처 역할을 합니다. 나는 이전 블로그 게시물에서 Generator와 Co에 대해 동일한 말을 했습니다.
// index.js // 用于引入babel,并且启动app.js require("babel-core/register"); require("./app.js");
co로 래핑된 함수 내에서는 다음 코드가 계속 실행되기 전에 단 하나의 비동기 실행만 완료됩니다. 그리고 오류 처리도 try and catch
를 통해 구현됩니다. 그러나 우리가 인정해야 할 것은 결국 비동기성을 위한 반복자가 존재하지 않는다는 것입니다. yield
및 *
의 의미는 비동기 함수 플래그를 나타내지 않습니다. 그리고 반복자는 co에 의해 구동되어야 하는데, 이는 우리가 상상했던 함수와 조금 다릅니다.
{ "presets": ["stage-3", "es2015"] }🎜
inserData
가 런처 드라이버 없이 직접 호출할 수 있는 실제 함수임을 알 수 있습니다. 물론 내부적으로도 yield
의 처리가 await
가 되는 것 외에는 큰 차이가 없다고 느낄 수도 있습니다. async/await는 비동기 프로그래밍의 의미에 더 가깝습니다. 🎜🎜그럼 질문은 어떻게 사용하느냐 입니다. 🎜🎜🎜사용 🎜🎜🎜처음부터 babel이 async Transform을 지원한다고 했으니 사용할 때 babel만 도입하면 됩니다. 물론, 서버 측과 브라우저 측의 처리 방법이 다를 수 있습니다. 시작하기 전에 필요한 async/await 컴파일 파일이 포함된 다음 패키지를 소개해야 합니다. 🎜🎜🎜🎜🎜rrreee🎜🎜브라우저 측🎜🎜🎜Babel은 원래 오래된 브라우저가 새로운 ES6 기능을 지원하고 개발 경험을 향상시킬 수 있도록 등장했습니다. 그래서 Babel은 처음부터 babel-cli 터미널을 통해 컴파일이 가능합니다. 또는 브라우저 측에서 컴파일할 바벨 파일을 도입하세요. 물론 이것들은 제가 가장 추천하는 것들이 아니므로 그냥 생략하겠습니다. 프런트엔드 정적 리소스 구성에서는 webpack이 현재 더 나은 솔루션입니다. 이는 정적 리소스의 모듈 종속성, 패키징 및 병합, 언어 전처리를 지원합니다. 물론 여기서는 바벨 처리를 참조합니다. 🎜🎜🎜🎜🎜rrreee🎜그래서 우리가 즐겁게 사용할 수 있어요. 🎜🎜🎜서버 측🎜🎜🎜상대적으로 말하면 백엔드는 프런트엔드보다 훨씬 더 많은 비동기 IO를 처리해야 하며 이 또한 더 필요합니다. 그렇다면 서버 측에 바벨을 어떻게 도입할까요? 🎜🎜사실 가장 간단하면서도 가장 번거로운 방법은 js 파일을 Babel을 통해 직접 컴파일해서 새 파일을 생성한 후 사용하는 것입니다. 물론 중복된 파일은 불가피합니다. 눈에 띄지 않게, 다른 방법을 시도해 보겠습니다. 🎜🎜공식적으로 제공되는 require Hook 방식을 사용합니다. 이름에서 알 수 있듯이 require를 통해 들어온 후 필요할 때 다음 파일을 Babel에서 처리합니다. CommonJs가 동기식 모듈 종속성이라는 것을 알고 있기 때문에 실행 가능한 방법이기도 합니다. 시작을 위해서는 실제로 프로그램을 실행하는 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 및 wait를 통해 비동기 메서드를 처리합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!