当前位置: 首页 > 后端技术 > Node.js

Node.js学习笔记深入浅出(4)

时间:2023-04-03 20:56:45 Node.js

异步编程Node是第一个将异步大规模引入应用层的平台。从其内部运行机制到API设计,无不透露着异步的感觉。1、函数式编程在JavaScript中,函数是一等公民,使用起来非常自由,无论是调用,还是作为参数,还是作为返回值。函数式编程是JavaScript异步编程的基础。1.1高阶函数高阶函数以函数为参数,或以函数为返回值的函数。函数夜(x){返回函数(){返回x;}}事件处理方式是基于高阶函数灵活的特点。ECMAScript5提供的高阶函数:forEach();map();reduce();reduceRight();filter();every();some();1.2部分函数的使用部分函数的使用是指创建对另一部分的调用-参数或变量已被预设的函数的使用。例子:vartoString=Object.prototype.toString;varisString=function(obj){returntoString.call(obj)=='[objectstring]';};varisFunction=function(obj){returntoString.call(obj)=='[objectfunction]';};示例改进(工厂模式):varisType=function(type){returnfunction(obj){retirntoString.call(obj)=='[object'+type+']';}};varisString=isType('字符串');varisFunvtion=isType('Funvtion');这种通过指定一些参数来生成新定制的形式是偏函数。2.异步编程的优点和难点2.1优点Node带来的最大特点是事件驱动的非阻塞I/O模型。非阻塞I/O可以让CPU和I/O相互独立等待,可以更好的利用资源。对于网络应用来说,并行带来的想象空间是巨大的。扩展是分布式的和云的。由于事件循环模型需要处理大量的请求,这些请求同时作用于单个线程,因此需要防止任何计算占用过多的CPU时间片。至于是计算密集型还是I/O密集型,只要计算不影响异步I/O的调度,就不构成问题。2.2难点难点:异常处理;写异步方法要遵循的原则:调用者传入的回调函数必须执行;异常正常传递给调用者判断;函数嵌套太深;阻塞代码;多线程编程;使用WebWorkers,使用消息机制是合理使用多核CPU的理想模型。WebWorkers可以解决占用CPU和减少阻塞UI渲染的问题,但不能解决UI渲染的效率问题。异步到同步;3.异步编程解决方案3.1事件发布/订阅模式事件监听模式是异步编程中广泛使用的一种模式,即回调函数的事件化,也称为发布/订阅模式。事件发布/订阅模式://订阅emitter.on("event1",function(message){console(message);})//publishemitter.emit("event1","Iammessage!");subscribeevent是高阶函数的应用。事件发布/订阅模式可以实现一个事件关联多个回调函数,这些回调函数又称为事件监听器。通过emit()发布事件后,消息会立即传递给当前事件的所有监听器执行。可以灵活地添加和删除监听器,方便事件与特定处理逻辑的关联和解耦。从另一个角度来看,事件监听器模式也是一种钩子机制,利用钩子将内部数据或状态导出给外部调用者。Node的事件发布/订阅机制的额外处理:如果一个事件添加的监听器超过10个,会给出警告;为了处理异常,EventEmitter对象对错误事件进行了特殊处理;从事件模块继承StreamNode一个对象继承EventEmitter的例子:varevents=require('events');函数流(){events.EventEmitter.call(this);}util.inherits(Stream,events.EventEmitter);使用事件队列解决雪崩问题once():监听器只能被执行一次,之后它与事件的关联被移除。使用once()解决雪崩问题。雪崩问题:在高流量高并发的情况下,缓存失效。这时候大量的请求同时涌入数据库,数据库无法同时承受如此大的查询请求,进一步影响了网站的整体响应速度。.调用数据库查询语句:varselect=function(callback){db.select("SQL",function(results){callback(results);});};多个异步方案之间的协作一般来说,事件和监听器的关系是一对多的,但是在异步编程中,事件和监听器的关系也是多对一的,也就是说一个业务逻辑可能依赖于两个结果。这就是回调嵌套太深的原因。由于多个异步场景下回调函数的执行不保证顺序,回调函数之间没有交集,所以需要使用第三方函数和第三方变量来处理异步协同的结果。用于监视次数的变量称为哨兵变量。EventProxy的原理EventProxy来源于Backbone的事件模块,是Model和View模块的基础功能。EventProxy将all视为一个事件流的拦截层,并在其中注入一些服务来处理单个事件无法解决的异步处理问题。EventProxy的异常处理EventProxy提供了两个实例方法fail()和done()来优化异常处理,让开发者专注于业务实现而不是异常捕获。3.2Promise/Deferred模式使用事件方法时,需要预先设置执行流程。甚至分支也需要预先设置,这是由发布/订阅模型的运行机制决定的。有没有办法先执行异步调用,延迟投递处理?答案是Promise/Deferred模式。Promises/APromise操作只会处于未完成、已完成和失败状态之一;Promise的状态只能从未完成状态转换为完成状态或失败状态,不能转换。完成状态和失败状态不能相互转化;一旦Promise的状态被改变,它就不能被改变;一个Promise对象只需要有一个then()方法。then()方法的要求:用于接收完成和错误状态的回调方法。当操作完成或发生错误时,会调用相应的方法;可选地支持进度事件回调作为第三种方法;then()方法只接受函数对象,其他对象将被忽略;then()方法返回的是一个支持链式调用的Promise对象;then()方法的作用是存储回调函数。为了完成整个过程,需要触发这些回调函数的执行。实现这些功能的对象通常称为Deferred,延迟对象。Promise和Dererred的区别:Promise作用于外部,通过then()方法暴露给外部,增加自定义逻辑;Dererred作用于内部,维护异步模型的状态;Promise是高级接口,而事件是低级接口。一旦定义了高层接口,底层接口就可以构建越来越复杂的场景。不易更改,低级接口不再具有灵活性。但是对于解决典型问题非常有效。Promise通过封装异步调用,实现了正向用例和反向用例的分离和逻辑处理延迟。Promise需要封装,但是功能强大,侵入性强。纯函数比较轻量级,但是功能比较弱。Promise中的多个异步协作类似于EventProxy。Promise进阶知识在API暴露方面,Promise方式比原来的事件监听和触发稍微优雅一些??。缺点是需要针对不同的场景封装不同的API,不如直接原生事件灵活。Promise的秘密其实就在于对队列的操作。*