java转nodeJs 从入门到还没有放弃

1,313 阅读7分钟

java转nodeJs 从入门到还没有放弃

JavaScript

在学习node之前,要知道node是用JavaScript写的项目,跑在v8虚拟机上的。所以需要了解JavaScript。 JavaScript就是一种可以在浏览器中运行的语言目的就是改变古老的静态页面网站。

JavaScript特有点

  • 代码存放在html文件的<scrpt>标签中,或者存放在其他.js文件中通过<script src="路径"> 加载。

  • 通过document对象查找获取html元素,比如getElementById() 方法可以查找Id获得对应id的html元素

  • 通过调用元素的innerHtml方法可以修改元素的内容

  • 事件 用户在浏览器上的一系列操作

    事件 描述
    onchange HTML 元素改变
    onclick 用户点击 HTML 元素
    onmouseover 用户在一个HTML元素上移动鼠标
    onmouseout 用户从一个HTML元素上移开鼠标
    onkeydown 用户按下键盘按键
    onload 浏览器已完成页面的加载

JavaScript与java不同点

  • 变量:

    var, let 定义变量,const定义常量,并不需要定义变量类型。并且变量可以先使用再定义。

  • 变量类型:

    • number: 不分intfloat,均为64位,

      Infinity 无穷大,NaN 非数字

      指数 Sign 值 (aka Fraction/Mantissa)
      11 bits (50 - 62) 1 bit (63) 52 bits (0 - 51)
    • String : 与java 基本一致

    • boolean

    • Null: 定义了但为负值的变量

    • 数组:数组是先定义类型的,所以一个数组中可以存放多种类型的变量。并且可以不再定义数组的时候制定长度

    • undifined:未定的变量,直接获取值/进行比较

    • 对象:同java,但是可以对象定义好之后再添加属性

      通过typeof可以获取变量类型

  • 变量转换 使用 类型对象(变量), 如:String(3.14), Inter("3.14");

  • 变量比较 == 只会对比 值,不会对比类型 如 5 == ‘5’ 会返还true。 === 会比较值和类型,等同于 java中的 ==

  • this

    • 在对象的方法中,this 表示该方法所属的对象。

    • 如果单独使用,this 表示全局对象。

    • 在函数中,this 表示global。

    • 在函数中,在严格模式下,this 是未定义的(undefined)。

    • 在事件中,this 表示接收事件的元素。

    • 类似 call() 和 apply() 方法可以将 this 引用到任何对象 (不建议使用)。

  • 函数式编程 javascript 中使用 (参数) => (方法实体) 等同于java中的 ->

node js

安装

brew install node

可以使用 nvm 管理node 版本。

brew install nvm

nvm ls-remot

nvm ls

nvm install <version>

nvm use <version>

模块

nodejs 有很多的模块。通过require 方法加载其他的模块。这样就可以使用其exports对象包含的方法。不在exports中的方法都无法被外部使用。可以通过module.exports 统一设置暴露的方法

Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。异步调用未node主要功能及用法。

事件

nodejs 使用事件驱动,(类似队列)。事件会绑定队列,事件会循环去绑定队列的请求并处理。通常不是直接使用事件类,而是使用集成了事件的 http,fs 等类。

  • on 方法绑定事件

  • emit 触发事件

    // 引入 events 模块
    var events = require('events');
    // 创建 eventEmitter 对象
    var eventEmitter = new events.EventEmitter();
    
    // 创建事件处理程序
    var connectHandler = function connected() {
        console.log('连接成功。');
    }
    
    // 触发 connection 事件
    eventEmitter.emit('connection');
    
    console.log("程序执行完毕。");
    

Callback

nodeJs是单线程的,为了提高代码的运行速度会将很多方法写成异步的,提高项目并发。第二点是为了延迟执行一个函数直到某一特定时机。

function add (x,y) {
  return x + y
}
function higherOrderFunction (x, callback) {
  return callback(x, 5)
}
higherOrderFunction(10, add)

[1,2,3].map((i) => i + 5)

const id = 'tylermcginnis'
$.getJSON({
  url: `https://api.github.com/users/${id}`,
  success: updateUI,
  error: showError,
})

但是如果多个callback 嵌套会导致代码可读性变差。

const id = 'tylermcginnis'
$("#btn").on("click", () => {
  $.getJSON({
    url: `https://api.github.com/users/${id}`,
    success: (user) => {
      $.getJSON({
        url: getLocationURL(user.location.split(',')),
        success (weather) {
          updateUI({
            user,
            weather: weather.query.results
          })
        },
        error: showError,
      })
    },
    error: showError
  })
})

有的会对这个代码进行优化。但callback的方式是将函数交给第三方运行,降低了对代码的控制度。又称之为控制反转

function getUser(id, onSuccess, onFailure) {
  $.getJSON({
    url: `https://api.github.com/users/${id}`,
    success: onSuccess,
    error: onFailure
  })
}
function getWeather(user, onSuccess, onFailure) {
  $.getJSON({
    url: getLocationURL(user.location.split(',')),
    success: onSuccess,
    error: onFailure,
  })
}
$("#btn").on("click", () => {
  getUser("tylermcginnis", (user) => {
    getWeather(user, (weather) => {
      updateUI({
        user,
        weather: weather.query.results
      })
    }, showError)
  }, showError)
})

promise

promis 的出现是为了解决上面提到了控制反转问题。增强对代码的控制度。promise的思路就像去快餐店点餐时,他有些需要更耗时的食品会提供一个蜂鸣器,再它做好了之后这个蜂鸣器会叫,提醒你可以去领食物了。但去与不去取决于你的想法。

promise 提供了三个不同状态 pendingfulfilledrejected

pending为初始的默认状态,等待状态。

fulfilled运行成功。

rejected运行失败。

下面是promise的实例,当promise 执行resolve时,代表运行成功,那么promise列表会执行传入.then()的方法,如果promise执行reject方法,代表执行失败,那么promise会执行传入.catch()中的方法。

function getUser(id) {
  return new Promise((resolve, reject) => {
    $.getJSON({
      url: `https://api.github.com/users/${id}`,
      success: resolve,
      error: reject
    });
  });
}

function getWeather(user) {
  return new Promise((resolve, reject) => {
    $.getJSON({
      url: getLocationURL(user.location.split(",")),
      success: weather => resolve({ user, weather: weather.city }),
      error: reject
    });
  });
}

$("#btn").on("click", () => {
  getUser("tylermcginnis")
    .then(getWeather)
    .then(data => {
      updateUI(data);
    })
    .catch(showError);
});

function updateUI(info) {
  $("#app").text(JSON.stringify(info));
}

Promise的 data对象会接收你传给resolve的数据,并将其变为他的参数。

下列代码可以对比callbacks和promise

// Callbacks 🚫
getUser("tylermcginnis", (user) => {
  getWeather(user, (weather) => {
    updateUI({
      user,
      weather: weather.query.results
    })
  }, showError)
}, showError)
// Promises ✅
getUser("tylermcginnis")
  .then(getWeather)
  .then((data) => updateUI(data))
  .catch(showError);

Async/await

promise的方案已经是比较好了。但是与正常的同步函数还是有些区别。所以TC39提出了Async/Await用于想同步代码一样写异步代码。

async 声明该函数内部写异步函数调用的代码了。await是声明哪些方式是异步调用的。注意getUser,getWeather两个方法是如上是promise声明的异步方法。

注意如果await等到的不是一个promise对象,那跟着的表达式的运算结果就是它等到的东西; 如果是一个promise对象,await会阻塞后面的代码,等promise对象resolve,得到resolve的值作为await表达式的运算结果。但promise对象也可能运行的 rejected,所以最好把 await 命令放在 try...catch 代码块中,或者await后的Promise添加catch回调 虽然await阻塞了,但await在async中,async不会阻塞,它内部所有的阻塞都被封装在一个promise对象中异步执行

$("#btn").on("click", async () => {
  try {
    const user = await getUser('tylermcginnis')
    const weather = await getWeather(user.location)
    updateUI({
      user,
      weather,
    })
  } catch (e) {
    showError(e)
  }
})

PM2

进程管理工具

安装

$ npm install pm2@latest -g
# or
$ yarn global add pm2

npm 与 yarn

npm都是javascritp 第三方库管理工具,类似于java的maven。帮你下载你保存在package.json文件中指定版本的第三方库。而yarn的产生主要是解决当时npm的一些问题。yarn主要有以下几个优点:

1. 超快的下载速度。
2. 离线下载,就是之前下载过一次,这个包就会放到电脑上的一个地方,下次别的项目要使用同一个包的时候就不用下载了,而是做一个链接,这样速度超级快。
3. 拥有 lockfile 文件,在 yarn 中叫 yarn.lock,这个文件会记录每次安装的包的版本的精确信息,这样,每次运行 yarn install 就会得到一模一样的依赖环境,而不是会出现个别包的版本不同,从而引发环境问题导致项目运行情况不同的尴尬事件。

不过当前npm5基本已经解决了这些问题,所以目前来说使用npm和yarn都是可以的。

* npm的package.json文件中会有~,^,*不同的符号,代表不同的意思

~ 会匹配最近的小版本依赖包,比如~1.2.3会匹配所有1.2.x版本,但是不包括1.3.0 ^ 会匹配最新的大版本依赖包,比如^1.2.3会匹配所有1.x.x的包,包括1.3.0,但是不包括2.0.0 * 这意味着安装最新版本的依赖包

命令

npm Yarn 说明
npm init yarn init 初始化某个项目
npm install/link yarn install/link 默认的安装依赖操作
npm install koa --save yarn add koa 安装某个依赖,并且默认保存到package
npm uninstall koa --save yarn remove koa 移除某个依赖项目
npm install koa --save-dev yarn add koa --dev 安装某个开发时依赖项目
npm update koa --save yarn upgrade koa 更新某个依赖项目
npm install koa --global yarn global add koa 安装某个全局依赖项目
npm publish/login/logout yarn publish/login/logout 发布/登录/登出,一系列NPM Registry操作
npm run/test yarn run/test 运行某个命令

express

Express 是基于nodejs的web开发框架。

安装与使用

yarn add express
const express = require('express')
const app = express()
const port = 3000 

app.get('/', (req, res) => res.send('Hello World!'))

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

router

express 可以根据请求url和method的不同调用不同的方法,会比使用原生node快捷很多。

// get
app.get('/example/f', function (req, res) {
  res.send('this is f')
});

//post
app.post('/example/a', function (req, res) {
    res.send('this is f')
});

// 设置多个
app.route('/book')
    .get(function (req, res) {
      res.send('Get a random book')
    })
    .post(function (req, res) {
      res.send('Add a book')
    })
    .put(function (req, res) {
      res.send('Update the book')
    });

// 所有的可以
app.all("/example/g", function (req, res) {
  res.send("this is g");
})

中间键

可以很简单的设置过滤器。

app.get("/example/b", function (req, res, next) {
  console.log("test")
  next()
}, function (req, res) {
  res.send('hello frim B!')
});

var cb0 = function (req, res, next) {
  console.log('CB0')
  next()
}
var cb1 = function (req, res, next) {
  console.log('CB1')
  next()
}
app.get('/example/c', [cb0, cb1], function (req, res) {
  res.send('Hello from C!')
})

// 使用use设置中间件,顺序不能变
app.use("/example/f", [cb0, cb1])
app.get('/example/f', function (req, res) {
  res.render('test', { title: 'Hey', message: 'Hello there!' })
})

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

错误处理

express 使用 errorHandler 接受并处理异常。并可以返还自定义的数据。

app.use(errorHandler);
function errorHandler (err, req, res, next) {
  console.log("erset")
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
}

app.use(function (err, req, res, next) {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

在中间键或者请求中调用next(err)会自动将错误发送给errorHandler处理。next() 反复中添加任意数据都会认为是发生错误。