首页 > 技术文章 > 初识node (三)

Jiazexin 2017-07-03 13:19 原文

一.async同步异步

铺垫:node是单线程异步的运行代码的
(感觉像同一时间干很多事情,快速的切换上下文)如果想开多线程 ,要开子进程

在node中能用异步,尽量不用同步性能很低

啥是同步?啥是异步?有啥区别?

异步编程是指由于异步I/O等因素,无法同步获得执行结果时,
在回调函数中进行下一步操作的代码编写风格,常见的如setTimeout函数、ajax请求等等。

示例:
	for (var i = 1; i <= 3; i++) {
		setTimeout(function(){
			console.log(i);
		}, 0);
	};
	这里大部分人会认为输出123,或者333。其实它会输出 444

要解决异步问题 就是回调函数,将后续的逻辑当做参数传递给这个函数
异步永远在同步之后执行,如果同步代码执行不能完成,异步永远不会触发
非阻塞(厨师)是异步的前置条件

这里就是我们要说的异步编程了。

高级函数的定义

这里为什么会说到高级函数,因为高级函数是异步编程的基础。

那什么是高级函数呢?
其实高级函数就是把函数作为参数或者是作为返回值。

示例:
	function test(v){
	  return function(){
		return v;
	  }
	}
如上就是把一个函数作为一个返回值。

二.箭头函数

啥是箭头函数?
箭头函数是[ES6]定义函数的新语法

普通函数↓
function a(b,c){
	return b+c
}
转换成箭头函数↓
let a=(b,c)=>b+c

[是不是很简洁?]
不只是有外观看起来不一样哦~

1.箭头函数不需要function声明

2.如果箭头后面是一个{}需要写return

**3.this指向箭头函数中没有this指向,所以this永远指向上一级,从而解决了一部分this指向问题 **

示例:
let obj = {
a:function () {
    setTimeout(()=> {
        console.log(this);
    });
}

};
obj.a.call(1);这里如果this不改成1,那就是a:function ()

**`但同时也因为this问题在node环境中是无法使用箭头函数的`这个稍后会做详解**

三.global-node全局对象

因为node在服务端运行所以没有window这一层作用域
也没有那些window下才有的事件
比如alert,onclick等等,node环境中也没有ajax.

但服务端有global global上的对象都可以直接访问 ->全局对象

global.a={b:12};
console.log(a);
输出{b:12}

如果在node环境console.log(global)会发现下面有很多或熟悉或陌生内置属性,下面着重了解几个典型

1.process(进程)

  • process 对象是一个 global (全局变量),提供有关信息,控制当前 Node.js 进程。作为一个对象,它对于 Node.js 应用程序始终是可用的,故无需使用 require( )来引入。

  • process模块用来与当前进程互动可以通过全局变量process访问,不必使用require命令加载。它是一个EventEmitter对象的实例

  • process对象提供一系列属性,用于返回系统信息.

  • process.pid:当前进程的进程号
  • process.version:Node的版本,比如v0.10.18
  • process.platform:当前系统平台,比如Linux
  • process.title:默认值为“node”,可以自定义该值
  • process.argv:当前进程的命令行参数数组。
  • process.env:指向当前shell的环境变量,比如process.env.HOME。
  • process.execPath:运行当前进程的可执行文件的绝对路径。
  • process.stdout:指向标准输出。
  • process.stdin:指向标准输入。
  • process.stderr:指向标准错误。

2.Buffer(缓存区)

先简单了解,以后再单独详说
Buffer 类是一个全局变量类型,用来直接处理二进制数据的。 它能够使用多种方式构建。

  • 在 ECMAScript 2015(ES6)引入 TypedArray 之前,JavaScript 语言没有读取或操作二进制数据流的机制。 Buffer 类被引入作为 Node.js API 的一部分,使其可以在 TCP 流或文件系统操作等场景中处理二进制数据流

  • Buffer 类的实例类似于整数数组,但 Buffer 的大小是固定的、且在 V8 堆外分配物理内存。 Buffer 的大小在被创建时确定,且无法调整

  • Buffer 类在 Node.js 中是一个全局变量,因此无需使用 require('buffer').Buffer。

  • 官方例子:

// 创建一个长度为 10、且用 0 填充的 Buffer。
const buf1 = Buffer.alloc(10);

// 创建一个长度为 10、且用 0x1 填充的 Buffer。 
const buf2 = Buffer.alloc(10, 1);

// 创建一个长度为 10、且未初始化的 Buffer。
// 这个方法比调用 Buffer.alloc() 更快,
// 但返回的 Buffer 实例可能包含旧数据,
// 因此需要使用 fill() 或 write() 重写。
const buf3 = Buffer.allocUnsafe(10);

// 创建一个包含 [0x1, 0x2, 0x3] 的 Buffer。
const buf4 = Buffer.from([1, 2, 3]);

// 创建一个包含 UTF-8 字节 [0x74, 0xc3, 0xa9, 0x73, 0x74] 的 Buffer。
const buf5 = Buffer.from('tést');

// 创建一个包含 Latin-1 字节 [0x74, 0xe9, 0x73, 0x74] 的 Buffer。
const buf6 = Buffer.from('tést', 'latin1'); 

3.console (控制台)

console 模块提供了一个简单的调试控制台,类似于 Web 浏览器提供的 JavaScript 控制台。
该模块导出了两个特定的组件:

  • 一个 Console 类包含 console.log() 、 console.error() 和 console.warn() 等方法,可以被用于写入到任何 Node.js 流。
  • 一个全局的 console 实例可被用于写入到 process.stdout 和 process.stderr。 全局的 console 使用时无需调用 require('console')。
  • 注意:全局的 console 对象的方法既不总是同步的(如浏览器中类似的 API),也不总是异步的(如其他 Node.js 流)
    例子,使用全局的 console:
console.log('你好世界');
// 打印: '你好世界'到 stdout。
console.log('你好%s', '世界');
// 打印: '你好世界'到 stdout。
console.error(new Error('错误信息'));
// 打印: [Error: 错误信息]到 stderr。

const name = '描述';
console.warn(`警告${name}`);
// 打印: '警告描述'到 stderr。

4.立即执行,定时(单次/多次)执行[clearImmediate]x[setImmediate]立即启动&[clearInterval]x[setInterval]定时循环启动&[clearTimeout]x[setTimeout]定时单次启动

Node.js 中的计时器是一种会在一段时间后调用给定的函数的内部构造。 定时器函数何时被调用取决于用来创建定时器的方法以及 Node.js 事件循环正在做的其他工作。定时器都是异步工作的但如果设置了多个定时器则按照设置定时器的顺序执行

如果设置了三个不同类的定时器在同一时间启动
那么将随机出现三种输出结果
setInterval(function(){
console.log(1)
},0);
setTimeout(function(){
console.log(2)
},0);
setImmediate(function(){
console.log(3)
})

module(node模块)

Node.js 有一个简单的模块加载系统。 在 Node.js 中,文件和模块是一一对应的(每个文件被视为一个独立的模块)。

当前模块的引用。 具体地说,module.exports 用于定义一个模块导出什么,且通过 require() 引入。

module 实际上不是一个全局变量,而是每个模块内部的。

在js中通过单利模式和闭包等方法来实现简单的模块化,但是单利模式有缺点:不能保证命名空间不冲突,而且如果命名过于复杂还会导致命名过长的麻烦
此时就通过require(模块)这种方法来引入外部模块,从而避免上述麻烦(不兼容)
[如何引入外部js文件的模块呢?]

  • 首先要在模块js文件中将模块(函数或变量)暴露导出有三种方法:
  • 第一种:给export增加属性
  • 第二种:给module.exports增加属性(引入后可直接调用)
  • 第三种不常用 是挂载在global的属性上
    例子:
function sum(...arr) {
let total = 0;
    arr.forEach(item=>total+=item);
    return total;
}
exports.sum = sum; 第一种方法
module.exports.sum = sum; 第二种方法
global.sum = sum; 第三种方法

相对应的三种导出方法也有对应的调用方法

导出后就可以引入了,在引用require方法
let sum=require('./sum') ->括号里写模块的路径
如果用exporas.sum = sum;这种方法
sum.sum(1,2,3)输出时就得这么写
如果使用module.exports.sum 这种方法
那就直接用就行了
sum.(1.2.3.4)

如需安装第三方模块请参考"初识npm"

推荐阅读