实现一个简单的 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}`);
  });
}
目录
相关文章
|
2月前
|
JavaScript 前端开发 API
探索后端技术:Node.js的优势和实际应用
【10月更文挑战第6天】 在当今数字化时代,后端开发是任何成功软件应用的关键组成部分。本文将深入探讨一种流行的后端技术——Node.js,通过分析其核心优势和实际应用案例,揭示其在现代软件开发中的重要性和潜力。
139 2
|
7天前
|
JavaScript 前端开发 API
深入理解Node.js事件循环及其在后端开发中的应用
本文旨在揭示Node.js的核心特性之一——事件循环,并探讨其对后端开发实践的深远影响。通过剖析事件循环的工作原理和关键组件,我们不仅能够更好地理解Node.js的非阻塞I/O模型,还能学会如何优化我们的后端应用以提高性能和响应能力。文章将结合实例分析事件循环在处理大量并发请求时的优势,以及如何避免常见的编程陷阱,从而为读者提供从理论到实践的全面指导。
|
10天前
|
存储 缓存 JavaScript
如何优化Node.js应用的内存使用以提高性能?
通过以上多种方法的综合运用,可以有效地优化 Node.js 应用的内存使用,提高性能,提升用户体验。同时,不断关注内存管理的最新技术和最佳实践,持续改进应用的性能表现。
|
2月前
|
运维 JavaScript Linux
容器内的Nodejs应用如何获取宿主机的基础信息-系统、内存、cpu、启动时间,以及一个df -h的坑
本文介绍了如何在Docker容器内的Node.js应用中获取宿主机的基础信息,包括系统信息、内存使用情况、磁盘空间和启动时间等。核心思路是将宿主机的根目录挂载到容器,但需注意权限和安全问题。文章还提到了使用`df -P`替代`df -h`以获得一致性输出,避免解析错误。
|
3月前
|
JavaScript 开发者
深入理解Node.js事件循环及其在后端开发中的应用
【8月更文挑战第57天】本文将带你走进Node.js的事件循环机制,通过浅显易懂的语言和实例代码,揭示其背后的工作原理。我们将一起探索如何高效利用事件循环进行异步编程,提升后端应用的性能和响应速度。无论你是Node.js新手还是有一定经验的开发者,这篇文章都能给你带来新的启发和思考。
|
2月前
|
JavaScript NoSQL 前端开发
使用 Node.js 和 MongoDB 构建实时聊天应用
【10月更文挑战第2天】使用 Node.js 和 MongoDB 构建实时聊天应用
|
3月前
|
JavaScript API 数据库
深入理解Node.js事件循环及其在后端开发中的应用
【9月更文挑战第3天】本文将深入浅出地介绍Node.js的事件循环机制,探讨其非阻塞I/O模型和如何在后端开发中利用这一特性来处理高并发请求。通过实际的代码示例,我们将看到如何有效地使用异步操作来优化应用性能。文章旨在为读者揭示Node.js在后端开发中的核心优势和应用场景,帮助开发者更好地理解和运用事件循环来构建高性能的后端服务。
|
4月前
|
JavaScript 开发者
深入理解Node.js事件循环及其在后端开发中的应用
【8月更文挑战第31天】 本文将带你走进Node.js的事件循环机制,通过浅显易懂的语言和实例代码,揭示其背后的工作原理。我们将一起探索如何高效利用事件循环进行异步编程,提升后端应用的性能和响应速度。无论你是Node.js新手还是有一定经验的开发者,这篇文章都能给你带来新的启发和思考。
|
4月前
|
JavaScript 前端开发 API
深入理解Node.js事件循环及其在后端开发中的应用
【8月更文挑战第29天】本文将深入浅出地介绍Node.js事件循环机制,并结合代码示例探讨其如何影响后端开发实践。我们将从事件循环的基本概念出发,逐步解析其工作原理和性能优化策略,旨在帮助开发者更好地理解和运用Node.js进行高效的后端开发。
|
4月前
|
JSON JavaScript 中间件
深入浅出Node.js后端开发之Express框架应用
【8月更文挑战第29天】本文将带领读者快速了解并掌握使用Express框架进行Node.js后端开发的基础和进阶知识。我们将一起探索Express的安装、基本使用方法,并通过实际代码示例学习如何搭建一个简单的Web服务器。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供有价值的指导和灵感。