Node.js的Reactor模式 与异步编程

解道jdon 2021-05-04 09:26:27
JS node node.js 模式 reactor


在Ruby on Rails和NodeJS开发者之间曾经引起宗教类的口水战:顺序编程风格 Vs 基于事件编程。目前大部分Web应用包括Ruby on Rails, Java Spring, Django都是使用顺序编程风格。顺序编程是非常简单和可读的,大部分开发者都是以顺序方式思考,喜欢将一个应用逻辑划分为顺序的时序步骤。顺序编程通常会导致堵塞I/O,因为线程是遵循先来后到的多任务方式,而不是一种协作式的多任务方式,而非堵塞I/O能够带来更好地扩展性和性能。

这是一篇有关Node.js的非堵塞reactive编程案例,文章以一个简单的根据id查询的RESTful案例为例,从堵塞IO谈到回调函数的使用,然后谈论如何在代码可扩展性和可读性之间取得平衡,引入Promise与Fibers编程。大意翻译如下:

下面代码是根据facebook的id查询用户事件数据的实现,顺序编程代码风格是如下(JS伪代码):

function getUserEvents(request,response){
var facebook_id = request.param('facebook_id');
try{
var user = db.users.findOne({fb_id:facebook_id});
var events = db.events.find({user_id:user.id});
response.write(events);
}catch(err){
response.status(500).send(err);
}
}
<p>

顺序编程通常会导致堵塞I/O,因为线程是遵循先来后到的多任务方式,而不是一种协作式的多任务方式。

下面我们逐步引入异步来提升这段代码。

基于回调的解决方案

为了解决堵塞的I/O问题,代码可以被划分为三个部分:

1. 在进行网络或IO调用前的过程处理。

2.网络或IO调用。

3.从网络或IO调用中得到返回数据的处理。

上面这三步都是分离执行的,然后它们在NodeJS的事件循环中被触发执行。

function getUserEvents(request,response){
var returnEvents = function(err,events){
if (err) respone.status(500).send(err);;
response.write(events);
});
var givenUserFindAndReturnEvents = function(err,user){
if (err) respone.status(500).send(err);;
db.events.find({user_id:user.id},returnEvents);
};
var findUserAndReturnEvents = function(){
var facebook_id = request.param('facebook_id');
db.users.findOne({fb_id:facebook_id}, givenUserFindAndReturnEvents);
}
findUserAndReturnEvents();
}
<p>

注意到请求和响应并没有被传递到子函数中,但是子函数可以访问request 和response,因为子函数是一个javascript 闭包. (当调用findUserAndReturnEvents函数时,相当于findUserAndReturnEvents -> givenUserFindAndReturnEvents ->returnEvents 这样一个流式调用)

这三个子函数都是异步执行的, givenUserFindAndReturnEvents 和 returnEvents是在findUserAndReturnEvents回调函数中触发执行的。

这三个子函数执行方式可以使用嵌套的lambda函数风格或findUserAndReturnEvents. givenUserFindAndReturnEvents.returnEvents 这种in-line方式。

这段代码有几个特点:

1.代码分离成网络调用前与网络调用后两个阶段

2.子函数调用者为了完成子函数任务必须传递一个回调函数。

3.顺序逻辑被表达成异步了

4.异步代码更加可扩展伸缩,但是也许增加响应延迟。

5.但是回调会引起可读性的问题:回调地狱 callback hell.

6.跟踪执行流程是困难的,因此称为意大利面条代码spaghetti-code.

7.非堵塞的API可能会限制妨碍你组织你的代码,有侵入性。

8.函数是有层次的。

基于Promise的解决方案

为了解决回调地狱,我们使用代码结构库如q promise. Promise库提供一些标准的代码风格和结构,使得代码更加易读。

var loadEventsForUser = function(err,user){
return db.events.find({user_id:user.id});
};
var findUser = function(){
var facebook_id = request.param('facebook_id');
return db.users.findOne({fb_id:facebook_id});
}
function getUserEvents(request,response){
var success = function(events){
response.write(events);
};
var error = function(err){
response.status(500).send(err);
};
findUser()
.then(loadEventsForUser)
.then(success)
.fail(error);
}
<p>

关键是最后一行的写法。

代码已经被划分为小的独立的函数,它们被以链条方式链接在一起,使用的是.then 和 .fail 函数. 另外一个重要特性是处理exception, 上面代码能够观察到错误然后调用相应的回调函数,错误处理被单独隔离了。

重要特点:

1.函数是扁平的,比如findUser能独立于loadEventsForUser函数调用。

2.将顺序编程代码切分成独立的可重用的函数并不总是很容易。

3.函数能够使用在其他流程被其他组件复用。

4.相比回调函数有更好的可读性。

5.比顺序编程有着更好地出错处理。

当然,我们还能更好地结合顺序编程可读优点和非堵塞可扩展的优点。待续..

[该贴被banq于2014-05-15 10:03修改过]

[该贴被admin于2014-05-15 14:24修改过]

[该贴被admin于2014-05-16 08:30修改过]

版权声明
本文为[解道jdon]所创,转载请带上原文链接,感谢
https://www.jdon.com/46372

  1. 21. Object oriented foundation "problems and solutions of object traversal"
  2. Discussion on hot micro front end: Google AdWords is a real micro front end
  3. Usecallback and usememo for real performance optimization
  4. 【前端圭臬】十一:从规范看 JavaScript 执行上下文(下)
  5. [front end standard] 11: Javascript execution context from the perspective of specification (2)
  6. Hexagonal六角形架构ReactJS的实现方式 - Janos Pasztor
  7. Transaction of spring's reactive / imperative relational database
  8. The implementation of hexagonal hexagonal reactjs Janos pasztor
  9. HTTP状态码:402 Payment Required需要付款 - mozilla
  10. HTTP status code: 402 payment required - Mozilla
  11. Factory mode, constructor mode and prototype mode
  12. Build the scaffold of react project from scratch (Series 1: encapsulating a request method with cache function based on Axios)
  13. Cocos Quick Start Guide
  14. Comparison of three default configurations of webpack5 modes
  15. A case study of the combination of flutter WebView and Vue
  16. CSS: BFC and IFC
  17. A common error report and solution in Vue combat
  18. JS: this point
  19. JS: prototype chain
  20. JavaScript series -- promise, generator, async and await
  21. JS: event flow
  22. Front end performance optimization: rearrangement and redrawing
  23. JS - deep and shallow copy
  24. JavaScript异步编程3——Promise的链式使用
  25. JavaScript asynchronous programming 3 -- chain use of promise
  26. Vue.js组件的使用
  27. The use of vue.js component
  28. How to judge whether a linked list has links
  29. Element UI custom theme configuration
  30. Text image parallax effect HTML + CSS + JS
  31. Spring的nohttp宣言:消灭http://
  32. Vue3 intermediate guide - composition API
  33. Analysis of URL
  34. These 10 widgets that every developer must know
  35. Spring's nohttp Manifesto: eliminate http://
  36. Learn more about JS prototypes
  37. Refer to await to JS to write an await error handling
  38. A short article will directly let you understand what the event loop mechanism is
  39. Vue3 uses mitt for component communication
  40. Characteristics and thinking of ES6 symbol
  41. Two way linked list: I'm no longer one-way driving
  42. Vue event and form processing
  43. Reactive TraderCloud实时外汇开源交易平台
  44. Reactive tradercloud real time foreign exchange open source trading platform
  45. Node.js REST API的10个最佳实践
  46. Ten best practices of node.js rest API
  47. Fiddler advanced usage
  48. Process from Vue template to render
  49. Promise up (asynchronous or synchronous)
  50. Principle and implementation of promise
  51. Vs code plug in sharing - run code
  52. Vue practical notes (1) introduction of Ant Design
  53. Vue actual combat notes (2) introduction of element plus
  54. Introduction to webpack
  55. Webpack construction process
  56. Vue notes
  57. The experience and lessons of moving from ruby megalith architecture to go microservice
  58. Using leancloud to add artitalk module to hexo blog
  59. Implementation of chrome request filtering extension
  60. Detailed introduction of beer import declaration elements and label quarantine [import knowledge]