nodejs基础教程之-异步编程promise/async/generator

news2024/12/23 19:05:38

1. 异步

所谓"异步",简单说就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段,比如,有一个任务是读取文件进行处理,异步的执行过程就是下面这样。

这种不连续的执行,就叫做异步。相应地,连续的执行,就叫做同步。

2.高阶函数

函数作为一等公民,可以作为参数和返回值

2.1 可以用于批量生成函数

  • 判断数据类型
let toString = Object.prototype.toString;
let isString = function (obj) {
  return toString.call(obj) == `[object String]`;
};
let isFunction = function (obj) {
  return toString.call(obj) == `[object Function]`;
};
let isType = function (type) {
  return function (obj) {
    return toString.call(obj) == `[object ${type}]`;
  };
};

2.2 可以用于需要调用多次才执行的函数

let after = function(times,task){
  return function(){
    if(times--==1){
      return task.apply(this,arguments);
    }
  }
}
let fn = after(3,function(){
  console.log(3);
});
fn();

3. 异步编程的语法目标,就是怎样让它更像同步编程,有以下几种

  • 回调函数实现
  • 事件监听
  • 发布订阅
  • Promise/A+ 和生成器函数
  • async/await

4.回调

所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数

fs.readFile("file.txt", function (err, data) {
  if (err) throw err;
  console.log(data);
});

这是一个错误优先的回调函数(error-first callbacks),这也是 Node.js 本身的特点之一。

5.回调的问题

5.1 异常的处理

try {
} catch (e) {}

异步代码时,try catch 无法捕获异常

let async = function (callback) {
  try {
    setTimeout(function () {
      callback();
    }, 1000);
  } catch (e) {
    console.log("捕获错误", e);
  }
};

async(function () {
  console.log(t); //undefined
});

因为这个回调函数被存放了起来,直到下一个事件环的时候才会取出,try 只能捕获当前循环内的异常,对 callback 异步无能为力。

Node 在处理异常有一个约定,将异常作为回调的第一个实参传回,如果为空表示没有出错。

async(function (err, callback) {
  if (err) {
    console.log(err);
  }
});

异步方法也要遵循两个原则

  • 必须在异步之后调用传入的回调函数
  • 如果出错了要向回调函数传入异常供调用者判断
let async = function (callback) {
  try {
    setTimeout(function () {
      if (success) callback(null);
      else callback("错误");
    }, 1000);
  } catch (e) {
    console.log("捕获错误", e);
  }
};

5.2 回调地狱

异步多级依赖的情况下嵌套非常深,代码难以阅读的维护

let fs = require("fs");
fs.readFile("template.txt", "utf8", function (err, template) {
  fs.readFile("data.txt", "utf8", function (err, data) {
    console.log(template + " " + data);
  });
});

6. 异步流程解决方案

6.1 事件发布/订阅模型

let fs = require("fs");
let emit = require("events");
let path = require("path");

let eve = new emit();

let html = {};
eve.on("ready", (key, value) => {
  html[key] = value;
  if (Object.keys(html).length == 2) {
    console.log(html);
  }
});

function render() {
  fs.readFile(
    path.resolve(__dirname, "./template.txt"),
    "utf8",
    (err, data) => {
      if (err) console.log("🚀 ~ fs.readFile ~ err:", err);
      // console.log("🚀 ~ fs.readFile ~ data:", data);
      eve.emit("ready", "template", data);
    }
  );
  fs.readFile(path.resolve(__dirname, "./data.txt"), "utf8", (err, data) => {
    if (err) console.log("🚀 ~ fs.readFile ~ err:", err);
    // console.log("🚀 ~ fs.readFile ~ data:", data);
    eve.emit("ready", "data", data);
  });
}

render();

在这里插入图片描述

6.2 哨兵模式

let fs = require("fs");
let path = require("path");

let after = function (times, callback) {
  let result = {};
  return function (key, value) {
    result[key] = value;
    if (Object.keys(result).length === times) callback(result);
  };
};

let done = after(2, function (result) {
  console.log(result);
});
function render() {
  fs.readFile(
    path.resolve(__dirname, "./template.txt"),
    "utf8",
    function (err, template) {
      done("template", template);
    }
  );
  fs.readFile(
    path.resolve(__dirname, "./data.txt"),
    "utf8",
    function (err, data) {
      done("data", data);
    }
  );
}
render();

6.3 Promise/Deferred 模式

6.4 生成器 Generators/ yield

当你在执行一个函数的时候,你可以在某个点暂停函数的执行,并且做一些其他工作,然后再返回这个函数继续执行, 甚至是携带一些新的值,然后继续执行。
上面描述的场景正是 JavaScript 生成器函数所致力于解决的问题。当我们调用一个生成器函数的时候,它并不会立即执行, 而是需要我们手动的去执行迭代操作(next 方法)。也就是说,你调用生成器函数,它会返回给你一个迭代器。迭代器会遍历每个中断点。
next 方法返回值的 value 属性,是 Generator 函数向外输出数据;next 方法还可以接受参数,这是向 Generator 函数体内输入数据

6.4.1 生成器的使用

function* foo() {
  var index = 0;
  while (index < 2) {
    yield index++; //暂停函数执行,并执行yield后的操作
  }
}
var bar = foo(); // 返回的其实是一个迭代器

console.log(bar.next()); // { value: 0, done: false }
console.log(bar.next()); // { value: 1, done: false }
console.log(bar.next()); // { value: undefined, done: true }

6.4.2 Co

co 是一个为 Node.js 和浏览器打造的基于生成器的流程控制工具,借助于 Promise,你可以使用更加优雅的方式编写非阻塞代码。

let fs = require("fs");
function readFile(filename) {
  return new Promise(function (resolve, reject) {
    fs.readFile(filename, function (err, data) {
      if (err) reject(err);
      else resolve(data);
    });
  });
}
function* read() {
  let template = yield readFile("./template.txt");
  let data = yield readFile("./data.txt");
  return template + "+" + data;
}
co(read).then(
  function (data) {
    console.log(data);
  },
  function (err) {
    console.log(err);
  }
);
function co(gen) {
  let it = gen();
  return new Promise(function (resolve, reject) {
    !(function next(lastVal) {
      let { value, done } = it.next(lastVal);
      if (done) {
        resolve(value);
      } else {
        value.then(next, (reason) => reject(reason));
      }
    })();
  });
}

6.5 Async/ await

使用 async 关键字,你可以轻松地达成之前使用生成器和 co 函数所做到的工作

6.5.1 Async 的优点

  • 内置执行器
  • 更好的语义
  • 更广的适用性
let fs = require("fs");
let path = require("path");

function readFile(filename) {
  return new Promise(function (resolve, reject) {
    fs.readFile(filename, "utf8", function (err, data) {
      if (err) reject(err);
      else resolve(data);
    });
  });
}

async function read() {
  let template = await readFile(path.resolve(__dirname, "./template.txt"));
  let data = await readFile(path.resolve(__dirname, "./data.txt"));
  return template + "+" + data;
}

let result = read();
result.then((data) => console.log(data));

6.3 Promise/Deferred 模式

6.4 生成器 Generators/ yield

当你在执行一个函数的时候,你可以在某个点暂停函数的执行,并且做一些其他工作,然后再返回这个函数继续执行, 甚至是携带一些新的值,然后继续执行。
上面描述的场景正是 JavaScript 生成器函数所致力于解决的问题。当我们调用一个生成器函数的时候,它并不会立即执行, 而是需要我们手动的去执行迭代操作(next 方法)。也就是说,你调用生成器函数,它会返回给你一个迭代器。迭代器会遍历每个中断点。
next 方法返回值的 value 属性,是 Generator 函数向外输出数据;next 方法还可以接受参数,这是向 Generator 函数体内输入数据

6.4.1 生成器的使用

function* foo() {
  var index = 0;
  while (index < 2) {
    yield index++; //暂停函数执行,并执行yield后的操作
  }
}
var bar = foo(); // 返回的其实是一个迭代器

console.log(bar.next()); // { value: 0, done: false }
console.log(bar.next()); // { value: 1, done: false }
console.log(bar.next()); // { value: undefined, done: true }

6.5.2 async 函数的实现

async 函数的实现,就是将 Generator 函数和自动执行器,包装在一个函数里。

async function read() {
  let template = await readFile("./template.txt");
  let data = await readFile("./data.txt");
  return template + "+" + data;
}

// 等同于
function read() {
  return co(function* () {
    let template = yield readFile("./template.txt");
    let data = yield readFile("./data.txt");
    return template + "+" + data;
  });
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2128009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#获取计算机信息

目录 效果 项目 代码 下载 效果 项目 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Management; n…

基于SSM的二手物品交易管理系统的设计与实现 (含源码+sql+视频导入教程+文档+PPT)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的二手物品交易管理系统7拥有两种角色 管理员&#xff1a;用户管理、分类管理、商品管理、订单管理、系统管理等 用户&#xff1a;登录注册、充值、收货、评价、收藏、购物车、订…

vue + Element UI table动态合并单元格

一、功能需求 1、根据名称相同的合并工作阶段和主要任务合并这两列&#xff0c;但主要任务内容一样&#xff0c;但要考虑主要任务一样&#xff0c;但工作阶段不一样的情况。&#xff08;枞向合并&#xff09; 2、落实情况里的定量内容和定性内容值一样则合并。&#xff08;横向…

【机器学习】马尔可夫随机场的基本概念、和贝叶斯网络的联系与对比以及在python中的实例

引言 马尔可夫随机场&#xff08;Markov Random Field&#xff0c;简称MRF&#xff09;是一种用于描述变量之间依赖关系的概率模型&#xff0c;它在机器学习和图像处理等领域有着广泛的应用 文章目录 引言一、马尔科夫随机场1.1 定义1.2 特点1.3 应用1.4 学习算法1.5 总结 二、…

使用 Apache Spark 和 Deequ 分析大数据集

在当今的数据驱动环境中&#xff0c;掌握使用 Apache Spark 和 Deequ 对大型数据集进行分析对于任何处理数据分析、SEO 优化或需要深入研究数字内容的类似领域的专业人士来说都至关重要。 Apache Spark 提供处理大量数据所需的计算能力&#xff0c;而 Deequ 提供质量保证层&am…

杨氏矩阵中查找某个数字是否存在(不能使用遍历)

杨氏矩阵&#xff1a; 有一个数字矩阵&#xff0c;矩阵的每行从左到右是递增的&#xff0c;矩阵从上到下是递增的 如图所示&#xff1a; i为行&#xff0c;j为列 如果要找9&#xff0c;先从arr【0】【2】处开始找&#xff0c;3<9,i,排除第一行&#xff0c;6<9,i,排除第…

基于SSM和VUE的药品管理系统(含源码+sql+视频导入教程+文档)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM和VUE的药品管理系统2拥有两种角色 管理员&#xff1a;药品管理、出库管理、入库管理、销售员管理、报损管理等 销售员&#xff1a;登录注册、入库、出库、销售、报损等 1.1 背景…

c++习题31-阶乘和

目录 一&#xff0c;题目 二&#xff0c;思路 三&#xff0c;代码 一&#xff0c;题目 描述 用高精度计算出 S1!2!3!…n!&#xff08;n≤50&#xff09;,其中“!”表示阶乘&#xff0c;例如&#xff1a;5!54321。 输入正整数n&#xff0c;输出计算结果S。 输入描述 …

微信公众号管理系统-需求整理

微信公众号管理系统-需求整理 文章目录 一、拟开发功能1.公众账号管理(必须)2.菜单管理(必须)2.1 跳转网页(view)2.2 发送消息(media_id)2.3 永久素材管理2.4 打开指定小程序(miniprogram)2.5 自定义点击事件(click)3.权限控制(必须)二、参与人员三、开发周期四、环境及…

二叉树的层序遍历-广度优先遍历

正常来讲二叉树的层序遍历 我们 使用递归 &#xff0c;来进行 就可以得到正确答案&#xff0c;但是有时候递归比较难以理解&#xff0c;我们今天用队列的形式 来进行二叉树的层序遍历 我们使用队列对二叉树进行层序遍历的核心思想有两个 1. 我们用队列 记录二叉树每一层的…

240908-结合DBGPT与Ollama实现RAG本地知识检索增强

A. 最终效果 B. 背景说明 DBGPT在0.5.6版本中开始支持Ollama&#xff1a;v0.5.6 版本更新 网友对其Web端及界面端的设置进行了分享&#xff1a; feat(model): support ollama as an optional llm & embedding proxy by GITHUBear Pull Request #1475 eosphoros-ai/DB-G…

【新手必看】Windows 上安装 Minio及简单使用

一&#xff0c;minio是什么&#xff1f; MinIO 是一个高性能、分布式的对象存储系统&#xff0c;专门用于存储大量非结构化数据&#xff0c;例如图片、视频、日志文件、备份等&#xff0c;且一个对象文件可以是任意大小&#xff0c;从几kb到最大5T不等。Minio是一个非常轻量的服…

【数学建模】2024年国赛成绩公布时间预测

经过三天三夜的奋战&#xff0c;2024年数学建模国赛也宣告结束&#xff0c;相信这几天超高强度的比赛也让大家精疲力竭了&#xff0c;所以经过几天的调整&#xff0c;大家都恢复过来了吧。能够在高强度的压力下坚持这么久&#xff0c;大家都超级厉害的&#xff01; 当然完整提交…

如何更好地解释你的想法并说服他人

这篇内容讨论了如何更有效地解释你的思想和想法&#xff0c;并说服他人。提出了几个原则和策略&#xff0c;如意想不到、简单性、具体化、故事性和情感。 中文 1 我最近读了一本关于有效沟通的书&#xff0c;名为《让你的想法更具说服力》&#xff08;《创意黏力学》&#x…

僵尸网络开发了新的攻击技术和基础设施

臭名昭著的 Quad7 僵尸网络&#xff08;也称为 7777 僵尸网络&#xff09;不断发展其运营&#xff0c;最近的发现表明其目标和攻击方法都发生了重大变化。 根据 Sekoia.io 的最新报告&#xff0c;Quad7 的运营商正在开发新的后门和基础设施&#xff0c;以增强僵尸网络的弹性&a…

ISAC: Toward Dual-Functional Wireless Networks for 6G and Beyond【论文阅读笔记】

此系列是本人阅读论文过程中的简单笔记&#xff0c;比较随意且具有严重的偏向性&#xff08;偏向自己研究方向和感兴趣的&#xff09;&#xff0c;随缘分享&#xff0c;共同进步~ Integrated Sensing and Communications: Toward Dual-Functional Wireless Networks for 6G and…

让人物照片跳舞vigen追影

本质上是一种视频换脸技术的升级版&#xff0c;视频换身。 项目体验地址&#xff1a;》》》魔搭社区《《《 选择“创作视频” 1.上传一张全身照片 2.选择一个包含动作的视频 3.点击“开始生成” 看效果 dreamoving-v1-2024-09-08-1000017-888139-result 动作的表现力还是很惊…

通过Docker实现openGauss的快速容器化安装

容器安装 本章节主要介绍通过 Docker 安装 openGauss&#xff0c;方便 DevOps 用户的安装、配置和环境设置。 支持的架构和操作系统版本 x86-64 CentOS 7.6 ARM64 openEuler 20.03 LTS 配置准备 使用 buildDockerImage.sh 脚本构建 docker 镜像&#xff0c;buildDockerIm…

【EI稳定,马来亚大学主办】2024年计算机与信息安全国际会议(WCCIS 2024,9月27-29)

2024年计算机与信息安全国际会议 (WCCIS 2024) 将于2024年9月27-29日召开。 会议旨在为从事计算机与信息安全的专家学者、工程技术人员、技术研发人员提供一个共享科研成果和前沿技术&#xff0c;了解学术发展趋势&#xff0c;拓宽研究思路&#xff0c;加强学术研究和探讨&…

动态规划(算法)---02.斐波那契数列模型_三步问题

题目链接&#xff1a; 面试题 08.01. 三步问题 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/three-steps-problem-lcci/description/ 一、题目解析 题目&#xff1a; 题目讲解&#xff1a; 我们先举例查看规律&#xff1a; 第一台阶&#xff1a;我…