Node Express上的重要技巧(适用于Java开发人员)

有时学习一种新的语言和语言栈似乎很陌生,至少对我来说是如此。 您知道,任何范例中的编程通常都是相同的,其余的只是语法糖,但一开始很难真正看到它。 特别是当StackOverflow没有您要寻找的答案时。

幸运的是,我为你们编写了关于Node Express的初学者指南。 我接到你了。 如果您涉足新领域,寻找新项目或更改新项目的堆栈,那么此博客对于所有Java开发人员都是一个明智的选择。 所以,让我们开始吧! 免责声明:我不是Node.js专家,但我学到了很难的方法,因此您不必🙇🏻️

这是一本长篇读物,这里是内容-继续前进:

  1. 🤔 Why node? How Node works 101. Useful information to determine if Node is for your project by diving into the V8 Engine.
  2. 📦 Library package management, build management, tasks and versioning What is npm and how to get started
  3. 🖋 JavaScript nice to knows Truthy, falsy, promises, variable declarations, function/class scope, functional programming, ESLint, logging and libraries
  4. 📥📤 Node Express Architecture, folder structure, secrets and configs, middleware, ORM
  5. ⌨️ TypeScript vs JavaScript I'll let you decide

🤔 Why Node? Is it for you? Here are some things to consider...

长期以来,Node(正式称为Node.js)一直是技术界的流行语。 看来它也不会很快到任何地方,那为什么要使用Node?

Node是使用Chrome的V8 JavaScript Engine构建的服务器端JavaScript运行时,它的主要吸引力在于其非阻塞I / O。 我知道...不阻塞谁? 好吧,这将确定Node是否适合您的项目。 在我看来,这两者之间是没有关系的(marmite振动)。

V8运行时引擎是单线程的,它使用事件循环 to execute events in the queue. In Java the thread queue has a number of tasks awaiting execution by a thread pool right? In this case an event is a task and an 事件循环 is the execution engine.

那么异步事件(例如发出API请求)呢? 事件循环是否等待API返回? 如果确实如此,那么延迟将是单个线程中的问题。 要解决此异步事件,请使用回调。

一个带有异步响应的回调事件,该事件添加到队列的后面。 现在可以同时执行其他事件,无需等待,因此“非阻塞I / O”😉

Express loop diagram author sarah ksiyer
Disclaimer2: I made an error in this diagram, task is meant to read 'event'

因此,Node可以表现更快用于事件驱动的用途,例如Web服务器,实时服务器(例如使用Web套接字),CRUD繁重的应用程序和API。

也因为这个原因,Node表现不佳处理大量任务,数据计算和阻止操作。

除了运行时之外,Node还使用JavaScript并从以下方面受益:

  • JS没有编译器,因此固有地具有较少的约束它具有灵活的模型,在使用NoSQL时非常有用它的平台独立性(然后Java也是如此,因此JS在这里没有赢得任何布朗尼分数)您可以在服务器端使用与客户端相同的语言,特别适合那些在全栈上工作的人

现在我们知道了什么是Node,何时使用它以及运行时带来了什么,我们可以进入包/构建管理,JavaScript基础知识,Node Express体系结构和TypeScript。

📦 Library package/build management, tasks and versioning

一世f you're familiar with npm you may want to jump ahead to the next section.

npm is comparable to Maven and Gradle. ñpmjs.com is an online catalog of JavaScript Libraries. npm (Nodes Package Manager) manages dependencies, package information and run tasks (like build, start or run tests).

To use npm, you would need to install both node and npm and use it through its CLI. Get started here.

每个npm项目都有一个package.json在根项目文件夹中。 该文件定义了项目名称,版本,作者,描述,许可证,依赖项以及更多。 项目依赖项下载到根目录中node_modules夹。

Dependencies

依赖有两种类型,项目依赖和devDependencies,仅在开发中才需要。 例如,也许仅开发人员才需要库CLI。 我会将npm的这一方面与Maven进行比较。

Tasks

通常,您的节点应用程序至少应具有启动,测试和构建任务-但您可以根据需要进行选择。 这些将由您的持续集成管道运行,我将把npm的这一方面与Gradle进行比较。

🖋JavaScript nice to knows

一世f you're familiar with JavaScript you may want to jump ahead to the next section.

 Loose objects

JavaScript,尽管可以认为它具有面向对象的功能,但实际上并没有键入(如果这是一个破坏交易的行为,我建议您研究TypeScript)。

所有类属性都被视为可选属性,函数参数也被视为可选属性。

function updateUserData(userObject){
  const { id, username, email } = userObject;
  //we cannot guarantee any of these properties were passed 
  //as part of this object or if any param was passed at all
}

Truthy and falsy

在开始编写JavaScript代码时,请牢记这两个方面,这仍然让我感到惊讶。

  • Truthy: Is whenever an expression is considered to return "true" which can be evaluated by 3 criterias,
    • it's not false (duh!)
    • the object is not nil (undefined or null)
    • it's not an empty object, for example an empty string ''
    Mozilla explain this pretty well.

  • Falsy: Is whenever an expression is considered to return "false" by being the inverse of the 3 above. again Mozilla explain it really well.

例如,if(0)的计算结果是什么?

let name = 'Sarah';

//good!
if(name){ 
  //checks if name is not empty, undefined or null
  //line below can be accessed
  console.log('Sarah exists!');
}


let balance = 0.0;

//bad!
if(balance){ 
  //javascript considers 0 as bitwise false 
  //we expect that if balance is not undefined or null this line will be executed
  //welcome to falsy!
  console.log('This will not get printed');
}

Functional Programming

如果您熟悉Java 8+函数式编程,那么JavaScript会更加容易。 这里有几件事要注意:

  • Array.prototype: You do not require a Stream to transform a collection into a functional type. You can chain functional programming operations to any array because you get it for free with Array.prototype. See Mozillas documentation these functions. Unlike Java there is no "terminal operation". You can manipulate that collection again and again and again, unlike Streams.

  • .map() .flatMap() .filter() .reduce(): These collection operators are the same as a Java. Some include .sort() is comparable to Java's .sorted() and .find() is comparable to Java's .findAny()

  • Method references: There are no method references in JavaScript

  • Arrow functions: Lambdas in Java are comparable to JavaScript's arrow function, caveat is instead of ->, its =>. JavaScript doesn't care if its a Consumer or a Supplier or a Function.

在Java中

Consumer<String> printString = str -> System.out.print(str);
printString.apply("Hello World!");

在JavaScript中

const printString = s => console.log(s);
printString('Hello World!');

Files

Casing

标准是使用kebab-case对JS文件进行大小写。 类名是PascalCase。 变量是camelCase。 明确一点,例如,如果您有一个字符串utils类,则类名应为StringUtils,文件名应类似于string-utils.js

File names

文件名不必与类名相关。 有时,文件名将在其中带有前缀和后缀的功能。 例如,用户REST控制器类的名称可以类似于user.controller.js。

var vs const vs let

变量是使用var,const或ES6来定义的。

  • var的范围不受其定义的代码块的限制。与Java完全不同。我们的范围仅限于其代码块,它是一个变量const's scope is limited to its code block and it is a constant (like final modifier)
for(var i=0; i < 10; i++){
  var forMessage = 'hello';
  let forLetMessage = ' world';
  const forConstMessage = '!!';
}

console.log(forMessage); //hello
console.log(forLetMessage); //Error
console.log(forConstMessage); //Error

Class/Function scope

与Java不同,JavaScript:

  • 是一种过程语言,如果您尝试使用超出其定义的功能,则超出范围文件名可以是任何东西许多“公共”类可以驻留在一个文件中(不要这样做,但实践不大)没有包,也没有公共,私有,受保护的或默认的访问修饰符为了公开授课,必须将其导出functions can be exported on their own

// Using EC5 exports
// file utils-one.js
const stringTrimmer = (str) => {
  return str.trim();
}

class StringUtil {
...
}

export.module = { StringUtil, stringTrimmer };


// OR using ES6 exports
// file utils-two.js
export function stringTrimmer(str) {
  return str.trim();
}

export class StringUtil {
...
}


// Function scope
//

printString('Hello'); // Bad, not accessible

printString(str){
  console.log(str);
}

printString('Hello'); // Good, accessible

Promises

承诺是异步对象,它承诺通过结果进行回调,该结果将被解析或拒绝。

Promises的一个很好的比喻是在餐厅下订单。 单线程工作者是服务员,订单是任务。

Restaurant gif
Shout out to Jo Franchetti' medium post of that awesome GIF

您可以向服务员下订单,然后他们会下订单,同时再下一个订单。 您的订单完成后,服务员将在下次免费时将其带给您。 注意,服务员直到订单完成才在柜台等待。

解析或拒绝值将返回两个函数, 。然后()和。抓住()分别。

  • 。然后如果回调成功,则箭头函数(lambda表达式)中的参数是异步调用的返回值,在这种情况下,这是您完成的命令。。抓住 is when the callback was rejected, an error was thrown. The param passed into the arrow function here is the error that was thrown.
Kitchen.orders('donuts')
.then((completedOrder) => console.log('Bon appetit'))
.catch((error) => console.error('Sorry, we're all out. Can I offer you a muffin?');

Logging

有很多很棒的JavaScript记录器库可供使用,列出了一些流行的库。 温斯顿,摩根或log4js。 它们每个都具有传输功能,日志可以传输到控制台,文件或云记录器(如Amazon CloudWatch或LogDNA)。

ESLint

尽管未编译JavaScript,但是您可以运行静态代码分析工具来使用ESLint识别有问题的模式。 与编译器不同,ESLint具有可配置的规则并将其加载到内部版本或IDE中。

I like AirBnB's ESLinter, its fairly comprehensive and thorough. It holds me to write to a good and consistent standard. To get started use npm to install the ESLinter or read the rules on their GitHub (packed with good, bad and very bad examples, it's pretty cool).

Libraries

最后,这是任何JavaScript项目中必不可少的一些库:

  • moment: A lightweight JavaScript date library for parsing, validating, manipulating, and formatting dates.
  • lodash: Lodash (previously underscore) is a JavaScript library which provides utility functions for common programming tasks using the functional programming paradigm.
  • axios: Axios is a promise-based HTTP client that works both in the browser and in a node environment.

📥📤 Node Express

我们已经讨论过Node,但是什么是Express?Express是Node的Web应用程序框架,旨在用于构建Web应用程序和API。它的流行是基于其简单性和易用性。(强调简单性,Spring生态系统提供了Express不提供的安全性和访问决策投票者)

Architecture

我发现3层架构是按照SOLID原则分离关注点的最干净的方法。

  • 控制者:此层包含用于API路由器端点,用户管理(授权,身份验证,用户会话),域访问和控制器(返回响应对象,标头,状态)之类的中间件的逻辑。服务:业务逻辑应该只存在于这一层资料存取:数据库模型

Alt Text

Folder structure (without test)

文件名示例(供用户使用) user.controller.js user.service.js user.model.js user.dto.js user.router.js

assets
└───i18n                # Translation .json files 
config                  
src
└───api                 # Express API logic
    └───controller      # Only should access Controller if authenticated and authorised
    └───middleware      # Auth, authorisation
    └───routers         # Endpoints 
└───data                
    └───dao             # DB queries
    └───entities        # Database models (entity)
└───dto                 # Data Transfer Objects
└───jobs                # Jobs like CRON
└───loaders             # Startup processes from app.js
└───services            # Business logic only lives here
└───subscribers         # Event handlers for async task
└───interfaces          # **Type declaration for DTO and Models files for Typescript
 │   app.js           # App entry point
 |   package.json       # npm tasks and dependencies
 |   .env           # Env vars and secrets

Middleware

中间件拦截具有某些功能的API路由逻辑。 中间件通常是您处理身份验证,授权,父子关系和控制器的地方。

Request middleware response flow author Sarah Ksiyer

中间件排序很重要,链接的逻辑随时可能中断。 我建议出于明显的原因首先进行身份验证。

//for all routes with /api will go through auth()
app.use('/api', auth())

function auth(req, res, next){
   //req is the API request object
   //res is the API response object, could be used to throw unauthorised
  // some logic..
  next();
  //next is used when things are good move on to the next middleware
}

For authentication I'd recommend looking into JWT (JSON Web Tokens). For password hash and salting I would highly recommend bcrypt.

 Secrets and configs

机密存储在根.env文件中。 通过过程访问 例如:.env文件:

PORT=8080
DB_DATABASE=my_db
DB_USER=sa
DB_PASSWORD=P4s5w0r1)

环境加载器:


// Environment Loader
// env.loader.js
const dotenv = require('dotenv');
dotenv.config();

export default {
  port: process.env.PORT || 3000,
  database: {
    name: process.env.DB_DATABASE,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD
  }
}

ORM - Object Relational Mapping

The two most popular ORMs are Sequelize and ŤypeORM. Sequelize is a JavaScript library that can be used by TypeScript as well. TypeORM is purely a TypeScript that heavily uses annotations on entities (models). TypeORM is closer to Hibernate with JPA style approach.

两种ORM都支持从RDBMS到NoSQL的多种数据库方言。

但是,您可能会高兴地听到,与Hibernate不同,这些ORM还可以处理迁移。 没错,您不再需要其他框架(例如FlywayDB或Liquibase)进行迁移。 将所有这些都放在一个地方真是太好了。

两者都有很好的文档和支持,您选择哪种依赖于您的编码风格。 这导致我进入下一个也是最后一个主题...

⌨️ TypeScript vs JavaScript

到目前为止,我们已经讨论了JavaScript,Node,Express,体系结构和ORM ...您可能正在考虑还有什么呢?

总结JavaScript是一种很棒的脚本语言,尤其是ECMAScript最新版本。 但是,JavaScript是一种过程语言,不会被编译,因此通常会在运行时发现错误,它具有松散的未类型化模型,难以确保按需使用函数/类,并且缺少有助于使用的访问修饰符。 基本设计模式,例如单例模式。

这就是TypeScript抢救的地方。 微软开发的TS是一种脚本语言,可以解决这些问题。 由于JavaScript并不是一种编译语言,因此TypeScript通过转译(简单地称为编译,因此我也将其转换)转换为JavaScript。

那么TypeScript具有JavaScript没有的功能呢?

  • 它被键入这不是程序性的它有一个“编译器”,它在运行时告诉您是否出了问题。Classes & Interfaces can have optional/required properties to keep benefits of a flexible model功能参数也可以是可选的/必需的它具有访问修饰符,注释,抽象和接口它支持依赖项注入

如此说来,您可以看到TS受C#的影响很大,因此自然而然地感到非常熟悉……这就是问题所在。

到目前为止,我一直试图保持公正,但是这是我的2便士。 我认为要真正受益于TypeScript提供的功能,您需要首先了解JavaScript提供的功能。 从跳转开始就使用TS,将带您以完全的OOP方式编写解决方案。 错过了使用更轻巧的服务器端脚本运行时(如Node)的意义。

TypeScript带来了很多好处在上面JavaScript已经做了什么。

from: https://dev.to//sarahk/top-tips-on-node-express-for-java-developers-341c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值