实现一个简单的 node 应用之 todo list1

简介: 实现一个简单的 node 应用之 todo list1

前言

学习目标:实现一个简单的 node 应用:todo list。

功能主要有:

  • 添加新任务
  • 清空任务列表
  • 展示所有任务
  • 操作任务
  • 修改任务标题
  • 修改任务状态
  • 删除单个任务


一、环境安装

  1. node
  2. npm


二、项目初始化

  1. 新建文件夹 mkdir node-todo-1
  2. 进入文件目录 cd node-todo-1
  3. 初始化包文件 npm init -y
  4. 新建文件 touch index.js


三、commander.js

官网链接:github.com/tj/commande…

1. 安装依赖

yarn add commander

2. 选项

// index.js
const { program } = require('commander');
program
  .option('-a --add', 'add an item')
  .option('-d, --delete', 'delete an item');
program.parse(process.argv);

.option(flags, desc) 用于定义选项

3. 看看效果

-h 是 --help 的缩写,默认用于显示帮助列表。

node index.js -h


1.jpg


4. 命令

看着文档,复制粘贴,摸索一下。

// index.js
const { program } = require('commander');
// 选项
program
  .option('-a --add', 'add an item')
  .option('-d, --delete', 'delete an item');
// 命令
program
  .command('add') // 在终端中输入:node index add task1 task2 task3
  .argument('<tasks...>', 'taskNameList') // 多参数处理
  .description('The cmd is used to add a task or more tasks.') // 命令描述
  .action((tasks) => { 
    console.log(tasks); // tasks is arguments list
    // 将参数列表合并处理成字符串
    const words = tasks.join(' ');
    console.log(words);
  })
program.parse(process.argv);

.command(nameAndArgs) 用于定义命令,命令名字和输入的参数可以写在一起!

.argument(arg) 用于定义参数,注意多参数的情况要用'<args...>'的形式!

.description(desc) 是命令的描述

.action(fn) 是输入命令后执行的回调

  • 执行看看,node index add task1 task2 task3


2.jpg


四、回调的分离

将 index.js 重命名为 cli.js,区别在于,将 .action() 的内容分离到 index.js 中统一管理。

index.js 中存放各种 api。(添加新任务、清除任务列表、展示所有任务等等)

1. Linux 命令

cat ~/.todo 表示:查看根目录下 .todo 文件中的内容

rm ~/.todo 表示:删除跟目录下的 .todo 文件

2. 添加新任务(功能 1)

  • 引入index.js,使用其中的方法。
// cli.js
const { program } = require('commander');
const api = require('./index')
// 选项
program
  .option('-a --add', 'add an item')
  .option('-d, --delete', 'delete an item');
// 命令
program
  .command('add') // 在终端中输入:node index add task1 task2 task3
  .argument('<tasks...>', 'taskNameList') // 多参数处理
  .description('The cmd is used to add a task or more tasks.') // 命令描述
  .action((tasks) => { 
    const words = tasks.join(' ');
    api.add(words); // 执行add方法,添加新任务到数据库!
  })
program
  .command('clear')
  .description('The cmd is used to clear all tasks.')
  .action((tasks) => { 
    // 将参数列表合并处理成字符串
    const words = tasks.join(' ');
    console.log(words);
  })
program.parse(process.argv);
  • add() 方法是 index.js 中的方法,它定义了触发 add Commander 命令时的处理逻辑。
  • 读取数据库文件 fs.readFile()
  • 添加一个新任务
  • 将新任务写入文件 fs.writeFile()
// index.js
const homedir = require('os').homedir(); // 获取home目录
const home = process.env.HOME || homedir; // 先从系统变量中获取
const path = require('path');
const dbPath = path.join(home, '.todo'); // 数据库路径(拼接而来的)
const fs = require('fs');
module.exports.add = (taskContent) => {
  // 1.读取文件
  fs.readFile(dbPath, {flag: 'a+'}, (err, data) => {
    if (err)  { 
      console.log(err); 
    } else {
      let list;
      try {
        // 此处的 data.toString() 应是一个JSON字符串,需要转换为真的数组!
        list = JSON.parse(data.toString());
      } catch (error) {
        // 如果报错,说明没有这样的数据,就创建一个新的数组!
        list = [];
      }
      // 2.添加一个任务
      const task = {
        title: taskContent,
        completed: false
      }
      list.push(task); // 将新建的任务推进 list 中
      // 3.将任务存储到文件
      const string = JSON.stringify(list); // 将 list 转换为 JSON 字符串
      // 将数据写入文件中
      fs.writeFile(dbPath, string, (err) => {
        if (err) {
          console.log(err);
          return;
        }
      })
    }
  })
}

Node.js 内置了很多模块,可以获取宿主环境中的某些信息。文档查阅:devdocs.io/

  • os 模块是操作系统模块,os.homedir() 可以获取系统的根目录路径。


3.jpg


  • process.env.HOME 可以获取进程中设置的 HOME 变量的对应路径。


4.jpg


  • path 模块是路径模块,path.join(...path) 可以拼接多个路径。


5.jpg


  • fs 模块是文件模块,
  • 文件读取:fs.readFile(filePath, options, (err, data) => {}) devdocs.io/node~14_lts…


6.jpg


  • 文件写入:fs.writeFile(filePath, data, (err) => {}) devdocs.io/node~14_lts…


7.jpg


最后,尝试一下:


8.jpg


3. 方法封装之面向接口编程

在“添加任务”的三个步骤中,希望一个步骤就是一条执行语句,而非现在这样一堆代码冗在那里!

也就是说先设计好接口,然后封装代码,以后使用某个功能时,只需要调用对应的接口即可。

  • 数据库中存放读写操作:
  • 注意 fs.readFile() 以及 fs.writeFile() 都是异步操作,因此不可以直接 return 结果。
  • 利用 Promise 对象改写异步操作,
  • 并且在出错时,直接 return reject(err);(直接返回失败的理由,不执行下面的代码。)
// db.js
const homedir = require('os').homedir();
const home = process.env.HOME || homedir;
const path = require('path');
const dbPath = path.join(home, '.todo');
const fs = require('fs');
const db = {
  // 1. 读取文件
  read (path = dbPath) {
    return new Promise ((resolve, reject) => {
      fs.readFile(path, {flag: 'a+'}, (err, data) => {
        if (err) return reject(err);
        let list;
        try {
          list = JSON.parse(data.toString());
        } catch (error) {
          list = [];
        }
        resolve(list);
      })
    })
  },
  // 2. 写入文件
  write (list, path = dbPath) {
    return new Promise((resolve, reject) => {
      const string = JSON.stringify(list);
      fs.writeFile(path, string, (err) => {
        if (err) return reject(err);
        resolve();
      })
    })
  }
}
module.exports = db;
  • 接口调用
// index.js
const db = require('./db');
module.exports.add = async (taskContent) => {
  // 1.读取文件
  const list = await db.read();
  // 2.添加一个任务
  list.push({title: taskContent, completed: false});
  // 3.将任务写入文件
  await db.write(list);
}

最后,尝试一下:


9.jpg


4. 清除任务列表(功能 2)

直接写入一个空的数组即可:

// cli.js
const { program } = require('commander');
const api = require('./index')
// 选项
program
  .option('-a --add', 'add an item')
  .option('-d, --delete', 'delete an item');
// 命令
// 命令1:添加新任务
program
  .command('add') // 在终端中输入:node index add task1 task2 task3
  .argument('<tasks...>', 'taskNameList') // 多参数处理
  .description('The cmd is used to add a task or more tasks.') // 命令描述
  .action((tasks) => { 
    const words = tasks.join(' ');
    api.add(words)
      .then(() => {
          console.log('添加成功!');
        })
      .catch(err => {
        console.log('添加失败!错误原因:' + err);
      });
  })
// 命令2:清空任务列表
program
  .command('clear')
  .description('The cmd is used to clear all tasks.')
  .action(() => { 
    api.clear()
      .then(() => {
            console.log('清除成功!');
          })
      .catch(err => {
        console.log('清除失败!错误原因:' + err);
      });
  })
program.parse(process.argv);
// index.js
const db = require('./db');
// 添加新任务
module.exports.add = async (taskContent) => {
  // 1.读取文件
  const list = await db.read();
  // 2.添加一个任务
  list.push({title: taskContent, completed: false});
  // 3.将任务写入文件
  await db.write(list);
}
// 清空任务列表
module.exports.clear = async (title) => {
  await db.write([]);
}

最后,尝试一下:

10.jpg


5. 展示所有任务(功能 3)

process.argv 表示用户输入在终端的参数个数,官网描述更好:


11.jpg


当用户仅输入 node cli.js 两项参数时,展示所有任务:

// cli.js
// 用户直接调用 node cli.js
if (process.argv.length === 2) {
  void api.showAll();
} else {
  program.parse(process.argv);
}
// inidex.js
// ...
// 展示所有任务
module.exports.showAll = async () => {
  // 1. 读出之前的任务
  const list = await db.read();
  // 2. 打印直接的任务
  list.forEach((task, index) => {
    console.log(`${task.completed ? '[x]' : '[_]'} ${index + 1} -> ${task.title}`);
  });
}
目录
相关文章
|
29天前
|
Web App开发 监控 JavaScript
【Node系列】创建第一个服务器应用
Node.js是一个基于Chrome V8引擎的JavaScript运行环境,可以用于构建高性能的网络应用程序。它采用事件驱动、非阻塞I/O模型,使得程序可以以高效地方式处理并发请求。
23 4
|
4天前
|
开发框架 JavaScript 中间件
中间件应用Koa.js(Node.js)
我们添加了两个中间件。第一个中间件记录请求的开始时间,并在下一个中间件执行完毕后计算并打印出请求的总时间。第二个中间件与之前的示例相同,它设置响应体为 "Hello World"
20 6
|
14天前
|
JavaScript 前端开发 持续交付
【专栏】Vue.js和Node.js如何结合构建现代Web应用
【4月更文挑战第27天】本文探讨了Vue.js和Node.js如何结合构建现代Web应用。Vue.js作为轻量级前端框架,以其简洁易懂、组件化开发、双向数据绑定和虚拟DOM等特点受到青睐;而Node.js是高性能后端平台,具备事件驱动、非阻塞I/O、丰富生态系统和跨平台优势。两者结合实现前后端分离,高效通信,并支持热更新、持续集成、跨平台和多端适配,为开发高性能、易维护的Web应用提供强有力的支持。
|
1月前
|
存储 JavaScript 前端开发
Angular 应用 node_modules 子文件夹 @types 的作用介绍
Angular 应用 node_modules 子文件夹 @types 的作用介绍
15 1
|
4天前
|
JavaScript 中间件 API
中间件应用Express.js(Node.js)
我们定义了一个名为 `logger` 的中间件函数。它接受请求对象、响应对象以及下一个中间件函数作为参数。当接收到请求时,它会打印出请求的 HTTP 方法和 URL,然后调用 `next()` 函数来将控制权传递给下一个中间件或路由处理器。我们使用 `app.use()` 方法将 `logger` 中间件添加到了应用级别的中间件堆栈中,这意味着它将对所有请求生效。
12 3
|
5天前
|
数据采集 JavaScript 数据可视化
Node.js爬虫在租房信息监测与分析中的应用
Node.js爬虫在租房信息监测与分析中的应用
|
13天前
|
运维 JavaScript Java
Serverless 应用引擎产品使用之阿里云Serverless函数计算中,在Node.js环境中执行jar文件如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
21 0
|
2月前
|
Web App开发 JavaScript 前端开发
深入浅出:Node.js 在后端开发中的应用与实践
【2月更文挑战第13天】本文旨在探讨Node.js这一流行的后端技术如何在现代Web开发中被应用以及它背后的核心优势。通过深入分析Node.js的非阻塞I/O模型、事件驱动机制和单线程特性,我们将揭示其在处理高并发场景下的高效性能。同时,结合实际开发案例,本文将展示如何利用Node.js构建高性能、可扩展的后端服务,以及在实际项目中遇到的挑战和解决方案。此外,我们还将讨论Node.js生态系统中的重要工具和库,如Express.js、Koa.js等,它们如何帮助开发者快速搭建和部署应用。通过本文的探讨,读者将获得对Node.js在后端开发中应用的深入理解,以及如何有效利用这一技术来提升开发效率
122 2
|
2月前
|
JavaScript 前端开发
node.js第四天--ajax在项目中的应用
node.js第四天--ajax在项目中的应用
27 0
|
3月前
|
JavaScript NoSQL Redis
深入浅出:使用 Docker 容器化部署 Node.js 应用
在当今快速发展的软件开发领域,Docker 作为一种开源的容器化技术,已经成为了提高应用部署效率、实现环境一致性和便于维护的关键工具。本文将通过一个简单的 Node.js 应用示例,引导读者从零开始学习如何使用 Docker 容器化技术来部署应用。我们不仅会介绍 Docker 的基本概念和操作,还会探讨如何构建高效的 Docker 镜像,并通过 Docker Compose 管理多容器应用。此外,文章还将涉及到一些最佳实践,帮助读者更好地理解和应用 Docker 在日常开发和部署中的强大功能。
149 0