Nodejs中的Javascript异步编程模式
Nodejs中的Javascript异步编程模式
什么非阻塞,异步I/O就不多说了。这里简单概括一下js的异步编程模式,但是别指望下面的东西能让你学会什么。最好的学习方式是实践。
PubSub模式,也就是订阅分发。
Node的API构架师因为太喜欢PubSub,所以就直接有了一个实体叫EventEmitter对象,几乎所有的I/O对象都继承了EvenEmitter。事件->事件处理器,是最基本的js设计模式。
Promise
尽管PubSub模式已经非常多才多艺,但是并不是适用于所有任务的万能工具,尤其是解决类似一次性事件的问题。比如对一次性任务的两种结果做不同的处理。 在之前的jQuery版本里
$.get('/mydata',{
succeess:onSuccess,
failure:onFail,
always:onAlways
})
在新版本的jQuery里
var promise = $.get('/mydata');
promise.done(onSuccess);
promise.fail(onFailure);
promise.always(onAlways);
jQuery的promise和CommmonJs的Promises/A大部分是一样的。 promise 还可以进行合并,比如
gameReady = $.when(tutorialPromise,gameLoadedPromise)
gameReady.done(startGame)
Promise越来越流行,就有越来越多的js库会要求异步函数必须返回promise对象,代替回调函数。
Async.js 工作流控制
前面都是对对象的抽象设计来控制异步的布局。但是,假设需要执行一组IO操作(或者并行,或者串行),该怎么办呢? 这个问题在Nodejs里面的确是必须面对的事情。以至于有了一个专有名词流程控制。Async.js是npm里面,人气相当高的 一个流程控制库。类似的还有一些轻量级的比如eventproxy.js,和step.js,都是非常棒的流程控制库。 比如
async.filter async.foreach 会并行处理数组
async.filterseries async.foreachSeries 会顺序处理数组
reject/rejectSeries 和filter 相反
map/mapSeries 1:1映射
reduce/reduceRight 值的逐步变换
detect/detectSeries 找到筛选器匹配的值
sortBy 产生有序副本
some 测试至少有一个值符合给定标准
every 测试是否所有值均符合给定标准
Async.js的精髓就是能够以最低的代码重复度来执行常见的迭代工作。
还有例如
async.series 异步函数顺序执行
async.parallel 异步函数并行执行
async.queue 动态队列排队技术,如下
async = require 'async'
worker (data,cb){
console.log(data)
cb()
}
concurrency = 2
queue = async.queue(worker,concurrency)
queue.push(1)
queue.push(2)
queue.push(3)
只要并发度不小于1,结果都是
1
2
3
区别是并发度为1需要三轮遍历,并发度为2需要2两轮遍历才能遍历完,并发度大于3的话,一轮就够了。
如果你的应用需要工作流程控制,那就需要找一个好的轮子,并且掌握它,我推荐上面提到的那些流程控制库。
worker对象的多线程技术
事件是多线程技术的替代品,但是多核cpu盛行的当下,我们需要多线程编程技术。那是否意味着就要放弃基于事件的编程呢?
多核任务调度是非常麻烦的,为了保持程序的纯洁性,最好让一个cpu单独执行一个任务,只是偶尔同步一下。 js中的worker就是这么干的。
网页版中的worker是HTML5标准的一部分,下面是个例子
//mian script
var worker = new Worker('boknows.js')
worker.addEventLisener('message',function(e){
console.log(e.data)
})
worker.postMessage('football')
worker.postMessage('baseball')
self.addEventListener(‘message’,function(e){
self.postMessage(‘Bo Nonws’+e.data)
})
在nodejs中cluster就是nodejs版的worker
cluster = 'cluster'
if(cluster.isMaster){
coreCount = require('os').cpus().length;
for(i=0;i<coreCount;i++){
cluster.fork()
cluster.on('death',function(worker){
console.log('Worker '+worker.pid+'has died')
})
}
}else{
process.exit()
}
输出如下
worker 15530 has died
worker 15532 has died
worker 15529 has died
worker 15531 has died
每一行输出对应一个cpu,但是worker到底是不是分配在一个独立的cpu上还要看底层的操作系统。
异步脚本加载
很多时候,我们需要为把.js放在head还是放在body后面担忧。利用defer,async这些属性也能处理很多情况。
这个时候可编程的条件加载出现了。比如yepnope这种轻量的脚本加载库
yepnope({
load:'js.js',
callback:function(){
console.log('ready')
}
})
还有Require.js/AMD的智能加载 加载示例
require(['moment'],function(moment){
console.log(moment().format('dddd'))
})
AMD模块定义示例
define('myApplication',['jquery'],function(){
$('<body>').append('<p>hello,async world</p>')
})
这样可以解决模块加载依赖等问题。
异步模式大概如此,但远不止如此。
Nodejs中的JavaScript异步编程模式
PubSub模式
Node.js 的 API 架构师非常喜欢发布/订阅(PubSub)模式,因此引入了一个名为 EventEmitter
的实体,几乎所有的 I/O 对象都继承自 EventEmitter
。事件与事件处理器是 JavaScript 中最基本的设计模式之一。
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event'); // 输出: an event occurred!
Promise
尽管 EventEmitter
模式非常强大,但它并不适合所有场景,特别是处理一次性事件的任务。在这种情况下,我们可以使用 Promise 来处理。
const getMyData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Data fetched successfully');
}, 2000);
});
};
getMyData()
.then(data => {
console.log(data); // 输出: Data fetched successfully
})
.catch(error => {
console.error(error);
});
Async.js 工作流控制
对于一组 I/O 操作(并行或串行),我们可以使用 async.js
库来进行工作流控制。
const async = require('async');
async.parallel([
function(callback) {
setTimeout(() => {
console.log('Task 1 completed');
callback(null, 'Result 1');
}, 1000);
},
function(callback) {
setTimeout(() => {
console.log('Task 2 completed');
callback(null, 'Result 2');
}, 2000);
}
], function(err, results) {
console.log(results); // 输出: [ 'Result 1', 'Result 2' ]
});
多线程技术
虽然事件驱动模型很强大,但在多核 CPU 环境下,我们可能需要更强大的多线程技术。Node.js 提供了 cluster
模块来实现这一需求。
const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
const cpuCount = os.cpus().length;
for (let i = 0; i < cpuCount; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
});
} else {
// 子进程的工作逻辑
}
异步脚本加载
为了优化页面加载性能,我们可以使用 yepnope
或 Require.js
进行异步脚本加载。
yepnope({
load: 'js.js',
callback: function() {
console.log('Script loaded and executed');
}
});
require(['moment'], function(moment) {
console.log(moment().format('dddd')); // 输出当前日期
});
结论
以上只是异步编程模式的一部分内容。Node.js 提供了多种工具来处理异步编程,掌握这些工具将帮助你编写高效、可维护的代码。希望本文能为你提供一些有用的参考。
嗯 目前成熟的就差不多这些
总结到位,哈哈。 在nodejs里边用的多的是基于回调的async和基于事件的eventproxy 浏览器端使用requirejs解决模块依赖是趋势,业务逻辑里的异步和nodejs差不多
Nodejs中的JavaScript异步编程模式
1. PubSub模式(订阅分发)
Node.js中的EventEmitter
对象几乎被所有I/O对象继承,它提供了事件触发与监听机制。通过这种方式,你可以订阅某个事件并在事件触发时执行相应的处理器。
示例代码:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('An event occurred!');
});
myEmitter.emit('event'); // 输出: An event occurred!
2. Promise
Promise是一种处理异步操作的方式,它可以更优雅地处理成功或失败的结果。
示例代码:
const fetch = require('node-fetch');
const promise = fetch('https://jsonplaceholder.typicode.com/todos/1');
promise.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
3. Async.js 工作流控制
Async.js 是一个流行的库,用于处理复杂的异步操作,如并行或顺序执行异步函数。
示例代码:
const async = require('async');
async.parallel([
function(callback) {
setTimeout(() => callback(null, 'one'), 200);
},
function(callback) {
setTimeout(() => callback(null, 'two'), 100);
}
], function(err, results) {
console.log(results); // 输出: [ 'one', 'two' ]
});
4. 多线程技术
在Node.js中,cluster
模块可以用来创建多个工作进程,每个进程都在独立的CPU核心上运行。
示例代码:
const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
const coreCount = os.cpus().length;
for (let i = 0; i < coreCount; i++) {
cluster.fork();
}
} else {
console.log(`Worker ${process.pid} started`);
}
5. 异步脚本加载
使用yepnope
或Require.js
可以实现更灵活的脚本加载策略。
示例代码:
const yepnope = require('yepnope');
yepnope({
load: 'script.js',
complete: function() {
console.log('Script loaded and executed.');
}
});
总结
以上介绍了几种在Node.js中常用的异步编程模式。通过理解和使用这些模式,可以更有效地管理复杂的异步逻辑,提升应用性能和可维护性。