『壹』 node怎么实现多线程
一、node单线程实现高并发原理
众所周知nodejs是单线程且支持高并发的脚本语言。可为什么单线程的nodejs可以支持高并发呢?很多人都不明白其原理,下面我来谈谈我的理解:
1. node的优点:I/O密集型处理是node的强项,因为node的I/O请求都是异步的(如:sql查询请求、文件流操作操作请求、http请求...)
a. 什么是异步?
异步:发出操作指令,然后就可以去做别的事情了,所有操作完成后再执行回调
异步的实现原理:
// 第一步:定义变量 let a = 1; // 第二步:发出指令,然后把回调函数加入异步队列(回调函数并没有执行) setTimeout(() => { console.log(a); }, 0) // 第三步:赋值,回调函数没有执行 a = 2; // 第四步:发出指令,然后把回调函数加入异步队列(回调函数并没有执行) setTimeout(() => { console.log(a); }, 0) // 第五步:赋值,回调函数没有执行 a = 3; // 当所有代码执行完毕,cpu空闲下来了,就会开始执行异步队列里面的回调函数 // 所以最后控制台输出:3 3
b. 什么是异步I/O?
异步I/O顾名思义就是异步的发出I/O请求
c. 虽然nodejs可以异步的发出I/O请求,但nodejs不支持多线程,为啥就可以支持高并发呢?
因为nodejs的I/O操作,底层是开启了多线程的
当同时有多个IO请求时,主线程会创建多个eio线程,以提高IO请求的处理速度
额外知识点:
d. 虽然nodejs的I/O操作开启了多线程,但是所有线程都是基于主线程开启的只能跑在一个进程当中还是不能充分利用cpu资源
pm2进程管理器可以解决这个问题
pm2 是一个带有负载均衡功能的Node应用的进程管理器.
e. cpu核数与线程之间的关系
在过去单CPU时代,单任务在一个时间点只能执行单一程序。之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程。虽然并不是真正意义上的“同一时间点”,而是多个任务或进程共享一个CPU,并交由操作系统来完成多任务间对CPU的运行切换,以使得每个任务都有机会获得一定的时间片运行。而现在多核CPU的情况下,同一时间点可以执行多个任务,具体到这个任务在CPU哪个核上运行,这个就跟操作系统和CPU本身的设计相关了
2. node的缺点:不擅长cpu密集型的操作
a. 什么是cpu密集型操作(复杂的运算、图片的操作)
// 这就是一个cpu密集型的操作 for (let i = 0; i < 1000000; i++) { console.log(i); }
b. nodejs为什么不擅长cpu密集型操作
因为nodejs是单线程的
『贰』 为什么要用nodejs服务
总的来说,Node.js的应用场景
1) 适合
JSON APIs——构建一个Rest/JSON API服务,Node.js可以充分发挥其非阻塞IO模型以及JavaScript对JSON的功能支持(如JSON.stringfy函数)
单页面、多Ajax请求应用——如Gmail,前端有大量的异步请求,需要服务后端有极高的响应速度
基于Node.js开发Unix命令行工具——Node.js可以大量生产子进程,并以流的方式输出,这使得它非常适合做Unix命令行工具
流式数据——传统的Web应用,通常会将HTTP请求和响应看成是原子事件。而Node.js会充分利用流式数据这个特点,构建非常酷的应用。如实时文件上传系统transloadit
准实时应用系统——如聊天系统、微博系统,但Javascript是有垃圾回收机制的,这就意味着,系统的响应时间是不平滑的(GC垃圾回收会导致系统这一时刻停止工作)。如果想要构建硬实时应用系统,Erlang是个不错的选择
2) 不适合
CPU使用率较重、IO使用率较轻的应用——如视频编码、人工智能等,Node.js的优势无法发挥
简单Web应用——此类应用的特点是,流量低、物理架构简单,Node.js无法提供像Ruby的Rails或者Python的Django这样强大的框架
NoSQL + Node.js——如果仅仅是为了追求时髦,且自己对这两门技术还未深入理解的情况下,不要冒险将业务系统搭建在这两个漂亮的名词上,建议使用MySQL之类的传统数据库
如果系统可以匹配Node.js的适用场景,那么是时候采取具体的措施来说服老板了。
说服自己老板采用Node.js的方式
构建一个简单的原型——花一周时间构建系统某一部分的原型是非常值得的,同时也很容易和老板在某一点达成一致,等到系统真的在某一部分应用了Node.js,就是打开局面的时候
寻找开发者——首先JavaScript语言的普及度很高,一般公司都不乏Web前端工程师,而此类工程师的学习门槛也非常低。这就意味着Node.js很容易招人,或者公司就隐藏了一些高手
强大的社区支持——Node.js社区非常活跃,吸引很多优秀的工程师,这就意味着公司可以很容易从社区得到免费或者付费的支持
系统性能考虑——JavaScript引擎Google V8,加之原生异步IO模型,使得Node.js在性能的表现非常出色,处理数以千计的并发请求非常轻松
『叁』 node.js可以写服务端吗
可以的,Nodejs就是为服务端而生的,说开了NodeJs只是JavaScript作为CommonJS的实现,使得JavaScript在服务器端有了用武之地,所以NodeJs从语法层面来说还是JavaScript。但是与客户端的JavaScript又有所区别。注意以下几点:
要学习NodeJs,必须有一定的JavaScript基础,理解事件模型,了解JavaScript的语法和特性,理解JavaScript面向对象编程
学习NodeJs类似于Python等代码组织的方式——包机制,require和exports。
一些基本的操作系统,HTTP等网络通信,数据库(尤其是非关系数据库),Web编程的知识有所了解。
具体的你可以访问NODEJS官网或者访问国内的社区、博客查询相关内容
『肆』 Nodejs学习笔记之NET模块
一,开篇分析
从今天开始,我们来深入具体的模块学习,这篇文章是这个系列文章的第三篇,前两篇主要是以理论为主,相信大家在前两篇的学习中,
对NodeJS也有一个基本的认识,没事!!!趁热打铁,让我们继续将NodeJS进行到底,好了废话不多说,直接进入今天的主题
“Net模块”
,那么”Net“应该如何理解那?
它是做什么用的那?(Net模块可用于创建Socket服务器或Socket客户端。NodeJS
的数据通信,最基础的两个模块是
Net
和
Http,前者是基于
Tcp
的封装,后者本质还是
Tcp
层,只不过做了比较多的数据封装,我们视为表现层)。
这里参考一下NodeJS
“http.js”
中的源码:
从图中不难看出
HttpServer继承了Net类,具有了相关的通信能力,做了比较多的数据封装,我们视为更高级的表现层。
扩展知识(以下是“inherits”的源码):
复制代码
代码如下:
exports.inherits
=
function(ctor,
superCtor)
{
ctor.super_
=
superCtor;
ctor.prototype
=
Object.create(superCtor.prototype,
{
constructor:
{
value:
ctor,
enumerable:
false,
writable:
true,
configurable:
true
}
});
};
功能是实现继承复用。
刚才做了一个简要的概述,里面有一些常用的概念,这里做个简短的概念普及介绍:
(1),TCP/IP------TPC/IP协议是传输层协议,主要解决数据如何在网络中传输。
(2),Socket------socket则是对TCP/IP协议的封装和应用(程序层面)。
(3),Http------HTTP是应用层协议,主要解决如何包装数据。
(4),网络七层模型------物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
总结一下:Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API)。
从而形成了我们知道的一些最基本的函数接口,比如Create、Listen、Connect、Accept、Send、Read和Write等等。
TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口
实际上,传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又是基于传输层的TCP协议的,而Socket本身不算是协议,就像上面所说,它只是提供了一个针对TCP或者UDP编程的接口。
二,体验一把
好了,概念我们也有了,来个例子:
1,建立server.js
复制代码
代码如下:
var
net
=
require('net')
;
var
server
=
net.createServer(function(c)
{
//
Connection监听器
console.log("服务器已连接")
;
c.on("end",
function()
{
console.log("服务器已断开")
;
})
;
c.write("Hello,Bigbear
!
")
;
c.pipe(c)
;
})
;
server.listen(8124,
function()
{
//
Listening监听器
console.log("服务器已绑定")
;
})
;
2,建立client.js
复制代码
代码如下:
var
net
=
require('net')
;
var
client
=
net.connect({
port:
8124
},function(){
//
connect监听器
console.log("客户端已连接")
;
client.write('Hello,Baby
!
')
;
});
client.on("data",
function(data)
{
console.log(data.toString())
;
client.end()
;
});
client.on("end",
function(){
console.log("客户端断开连接")
;
})
;
分析一下:
服务端------net.createServer创建一个
TCP
服务,这个服务绑定(server.listen)在
8124
这个端口上,创建
Server
后我们看到有一个回调函数,
在调用上面函数的时候传入一个参数,这个参数也是函数,并且接受了
socket
,这个由其他方法构造的一个管道(pipe),他的作用就是用来数据交互的。
pipe
是需要
Client
跟
Server
打招呼才能建立的,如果此刻没有客户端访问
Server,这个
socket
就不会存在了。
客户端------net.connect顾名思义,就是连接到服务端,第一个参数是对象,设置端口(port)为
8124,也就是我们服务器监听的端口,由于没有设置
host
参数,那默认就是
localhost
(本地)。
在
Server
中,socket
是管道的一端,而在
client
中,client
本身就是管道的一端,如果是多个客户端连接
Server,Server
会新建多个
socket,每个
socket
对应一个
client。
运行结果:
三,案例引入
(1),下面代码仅仅是服务器向客户端输出一段文本,完成服务端到客户端的单向通讯。
复制代码
代码如下:
//
Sever
-->
Client
的单向通讯
var
net
=
require('net');
var
chatServer
=
net.createServer();
chatServer.on('connection',
function(client)
{
client.write('Hi!
');
//
服务端向客户端输出信息,使用
write()
方法
client.write('Bye!
');
client.end();
//
服务端结束该次会话
});
chatServer.listen(9000);
Telnet测试一下:telnet127.0.0.1:9000
执行
telnet后,与服务点连接,反馈
Hi!
Bye!
的字符,并立刻结束服务端程序终止连接。
如果我们要服务端接到到客户端的信息?
可以监听
server.data
事件并且不要中止连接(否则会立刻结束无法接受来自客户端的消息)。
(2),监听
server.data
事件并且不要中止连接(否则会立刻结束无法接受来自客户端的消息)。
复制代码
代码如下:
//
在前者的基础上,实现
Client
-->
Sever
的通讯,如此一来便是双向通讯
var
net
=
require('net');
var
chatServer
=
net.createServer(),
clientList
=
[];
chatServer.on('connection',
function(client)
{
//
JS
可以为对象自由添加属性。这里我们添加一个
name
的自定义属性,用于表示哪个客户端(客户端的地址+端口为依据)
client.name
=
client.remoteAddress
+
':'
+
client.remotePort;
client.write('Hi
'
+
client.name
+
'!
');
clientList.push(client);
client.on('data',
function(data)
{
broadcast(data,
client);//
接受来自客户端的信息
});
});
function
broadcast(message,
client)
{
for(var
i=0;i<clientList.length;i+=1)
{
if(client
!==
clientList[i])
{
clientList[i].write(client.name
+
"
says
"
+
message);
}
}
}
chatServer.listen(9000);
上面是不是一个完整功能的代码呢?我们说还有一个问题没有考虑进去:那就是一旦某个客户端退出,却仍保留在
clientList里面,这明显是一个空指针。
(3),处理clientList
复制代码
代码如下:
chatServer.on('connection',
function(client)
{
client.name
=
client.remoteAddress
+
':'
+
client.remotePort
client.write('Hi
'
+
client.name
+
'!
');
clientList.push(client)
client.on('data',
function(data)
{
broadcast(data,
client)
})
client.on('end',
function()
{
clientList.splice(clientList.indexOf(client),
1);
//
删除数组中的制定元素。
})
})
NodeTCPAPI已经为我们提供了
end
事件,即客户端中止与服务端连接的时候发生。
(4),优化broadcast
复制代码
代码如下:
function
broadcast(message,
client)
{
var
cleanup
=
[]
for(var
i=0;i<clientList.length;i+=1)
{
if(client
!==
clientList[i])
{
if(clientList[i].writable)
{
//
先检查
sockets
是否可写
clientList[i].write(client.name
+
"
says
"
+
message)
}
else
{
cleanup.push(clientList[i])
//
如果不可写,收集起来销毁。销毁之前要
Socket.destroy()
用
API
的方法销毁。
clientList[i].destroy()
}
}
}
//Remove
dead
Nodes
out
of
write
loop
to
avoid
trashing
loop
index
for(i=0;i<cleanup.length;i+=1)
{
clientList.splice(clientList.indexOf(cleanup[i]),
1)
}
}
注意的是一旦
“end”
没有被触发,会出现异常,所以才做优化工作。
(5),NetAPI中还提供一个
error
事件,用于捕捉客户端的异常
复制代码
代码如下:
client.on('error',
function(e)
{
console.log(e);
});
四,总结一下
1,理解开篇的相关概念
2,认识Http与Net模块之间的关系
3,结合本文的例子,查阅相关api去实践
4,socket客户端与服务器端之间的通信思想
5,有兴趣可以完善一下那个聊天室的例子
『伍』 web前端开发常用工具有哪些
1、jQuery
jQuery由于其无限的教程,没有跨平台/浏览器问题,优秀的用户界面,大量的插件以及它的轻量,岁喊快速和快速学习等特点而脱颖而出。超过70%的受访者选择jQuery作为他们的前端库,它是一个快速,轻量级和简洁的JavaScript库,主要用于HTML文档遍历、事件携含处理、动画和用于快速Web开发的Ajax交互。从本质上讲,jQuery最适合需要快速开发的应用程序。
2、Bootstrap
超过65%的开发者选择Bootstrap作为他们最喜欢的框架来使用,它是一个用HTML、CSS和JS开发的开源工具包。Bootstrap的广泛流行主要是因为它的简单使用、优秀的社区以及大量的文章和教程、第三方插件和扩展、主题构建器等。
3、Angular
如果你打算构建一个动态且强大的单页应用程序,Angular就是你需要的框架。Angular是高度模块化的,因此非常适合与团队分开大型工作,并且使测试和调试变得轻松。功能优先的方法使Angular更加专注于功能,使开发人员的工作更轻松。此外,它还有来自Google社区的出色工具和支持。
4、NPM
NPM是Node的包管理器。借助NPM,开发人员可以安装各种模块进行Web开发,共享和借用软件包,并管理私有开发。它由网站、命令行界面(CLI)和注册表三个不同的组件组成。
5、Webpack
Webpack是现代JavaScript应用程序的模块打包程序,它将前端开发所辩雀笑需的所有资源(如JavaScript、字体和图像)集中到一个地方。如果你正在开发复杂的前端,这特别有用。你可以去通过部署具有的WebPack Web应用程序,以获取有关的WebPack起来和运行。
除了以上工具,还有Sass、React等,根据企业所用工具的不同,你需要掌握的工具也不一样。