Promise的链式调用案例讲解

这篇具有很好参考价值的文章主要介绍了Promise的链式调用案例讲解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


这篇文章通过一个小案例,一起了解Promise的链式调用

案例分析

这里我模拟某个语音功能的操作流程,每隔一秒钟,我去模拟一个操作,先看下面代码:

const chain = Promise.resolve();
  chain
    .then(() => {
      // 1.模拟开始说话 打开vc vc状态speaking
      vc.value?.changeState("SPEAKING");
    })
    .then(() => {
      // 2. 语音输入
      setTimeout(() => {
        question.value = "你好";
      }, 1000);
    })
    .then(() => {
      // 2. 继续输入
      setTimeout(() => {
        question.value = "你好,欢迎使用vc";
      }, 1000);
    });

问题解读

有没有发现上面代码有什么不妥的地方吗?
这段代码是一个使用 Promise 链式调用的示例,主要用于模拟某个语音控制(VC)功能的操作流程。

  1. 初始化 Promise 链
const chain = Promise.resolve();

这里,Promise.resolve() 创建了一个立即解析(fulfilled)的 Promise,它返回一个 Promise 对象,这个对象的状态已经被设置为解析(fulfilled),所以任何连接到这个 Promise 的 .then() 方法都会立即执行。
2. 第一个 .then()

.then(() => {
  // 1.模拟开始说话 打开vc vc状态speaking
  vc.value?.changeState("SPEAKING");
})

当 Promise 解析后,第一个 .then() 会被执行。这里,它模拟了开始说话的动作,并尝试更改 vc(可能是一个代表语音控制的对象)的状态为 “SPEAKING”。使用了可选链(?.),意味着如果 vcvc.valuenullundefined,则不会调用 changeState 方法,也不会报错。
3. 第二个 .then()

.then(() => {
  // 2. 语音输入
  setTimeout(() => {
    question.value = "你好";
  }, 1000);
})

第二个 .then() 模拟了语音输入的过程。它使用 setTimeout 来模拟一个延迟(这里是1秒),之后更改 question.value 的值为 “你好”。这可以理解为在1秒后,模拟用户通过语音输入了“你好”。

但这里有一个问题:由于 setTimeout 是异步的,而 .then() 的回调函数是立即返回的,所以下一个 .then() 可能会在 setTimeout 的回调执行之前就被调用。
4. 第三个 .then()

.then(() => {
  // 3. 继续输入
  setTimeout(() => {
    question.value = "你好,欢迎使用vc";
  }, 1000);
})

第三个 .then() 的逻辑与第二个相似,但它在 question.value 中添加了更多的文本。但这里又有一个同样的问题:它可能在上一个 setTimeout 执行完之前就运行了。

修改建议

  • 连续的 .then() 调用之间并没有真正的依赖关系,它们只是简单地串联在一起。但由于 setTimeout 的使用,它们之间的执行顺序可能并不是你预期的。
  • 如果你希望每一步都在前一步的 setTimeout 之后执行,你应该将每一步都放在一个返回 Promise 的函数中,并在该 Promise 解析后再进行下一步。

修正后的代码可能类似于这样(使用了 async/await 和自定义的延迟函数):

async function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function simulateVC() {
  // 1.模拟开始说话 打开vc vc状态speaking
  vc.value?.changeState("SPEAKING");

  await delay(1000);
  // 2. 语音输入
  question.value = "你好";

  await delay(1000);
  // 3. 继续输入
  question.value = "你好,欢迎使用vc";
}

simulateVC();

这样,每一步都会在前一步之后准确地执行。

还有什么其他方式实现这种延迟调用链的吗?

除了使用 async/await 和 Promise 之外,还有其他几种方式可以实现延迟调用链。以下是其中的一些方法:

1. 回调函数(Callback)

使用回调函数是最基本的方法之一,但它可能会导致所谓的“回调地狱”(Callback Hell),特别是当你有多个依赖的异步操作时。

function delayedLog(msg, delay, callback) {
  setTimeout(() => {
    console.log(msg);
    callback && callback();
  }, delay);
}

delayedLog('Hello', 1000, () => {
  delayedLog('World', 1000);
});

2. Promise 链

你已经展示了 Promise 链的方式,但是为了更清晰地表达每一步的延迟,我们可以稍微调整一下代码结构。

function delayedPromise(msg, delay) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(msg);
      resolve();
    }, delay);
  });
}

delayedPromise('Hello', 1000)
  .then(() => delayedPromise('World', 1000));

3. Promise.all 和数组映射

如果你有一个需要依次延迟执行的任务数组,你可以使用 Promise.all 结合数组的 map 方法。不过要注意,Promise.all 会等待所有 Promise 都解决,但如果你想要依次执行它们,你应该使用 reduce

const tasks = ['Hello', 'World'];
const delays = [1000, 1000];

tasks.reduce((chain, task, index) => {
  return chain
    .then(() => new Promise(resolve => {
      setTimeout(() => {
        console.log(task);
        resolve();
      }, delays[index]);
    }));
}, Promise.resolve());

4. Generator 函数和 co 库

在 ES6 之前,Generator 函数和第三方库如 co 被用来以更同步的方式编写异步代码。

const co = require('co'); // 需要安装 co 库:npm install co

function* generatorFunction() {
  yield delayedLog('Hello', 1000);
  yield delayedLog('World', 1000);
}

function delayedLog(msg, delay) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(msg);
      resolve();
    }, delay);
  });
}

co(generatorFunction());

5. Observable(如 RxJS)

使用 Observable 也是一种处理异步数据流的方法,特别是在处理多个、复杂的异步事件时。RxJS 是一个流行的库,它提供了 Observable 的实现。

const { of } = require('rxjs');
const { delay, concatMap } = require('rxjs/operators');

of('Hello')
  .pipe(
    delay(1000),
    concatMap(x => of(x).pipe(delay(0))), // 仅仅是为了展示 concatMap 的使用
    concatMap(x => of(`${x}, World`).pipe(delay(1000)))
  )
  .subscribe(console.log);

在这个例子中,concatMap 被用来确保每个操作都在前一个操作完成后才执行。RxJS 提供了丰富的操作符来处理各种异步场景。

6. Async/Await 和 for…of 循环

如果你有一个异步操作的数组,并且想要依次执行它们,你可以使用 for...of 循环与 async/await 结合。

async function sequentialExecution(tasks) {
  for (const task of tasks) {
    await task();
  }
}

const tasks = [
  () => delayedLog('Hello', 1000),
  () => delayedLog('World', 1000)
];

sequentialExecution(tasks);

在这个例子中,sequentialExecution 函数会依次等待每个异步任务完成。tasks 数组包含了返回 Promise 的函数。

选择哪种方法取决于你的具体需求和你对每种技术的熟悉程度。在现代 JavaScript 开发中,async/await 和 Promise 链通常是最受欢迎的选择,因为它们提供了清晰和简洁的异步代码结构。文章来源地址https://www.toymoban.com/news/detail-821598.html

到了这里,关于Promise的链式调用案例讲解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • XML基础知识讲解

    XML(eXtensible Markup Language)是一种用于描述数据的标记语。 它以纯文本的方式存储数据,并使用标签来标记数据的结构和含义。XML被设计 用于传输和存储数据,同时也可作为配置文件和数据交换的格式 。 创建一个xml文档,必须要有文档说明且必须放在第一行 version(必须要有

    2024年02月13日
    浏览(37)
  • CSS的基础知识讲解

    一般来说我们CSS就是我们对浏览器的第二个操作,就是给网页穿衣服.让网页变得更好看. 在CSS中,选择器用于选择HTML文档中的元素,从而将样式应用于这些元素。选择器通常基于元素的标签名、类名、ID、属性值或父子关系等特征来进行匹配。 标签选择器:选择某个 HTML 标签

    2024年02月05日
    浏览(43)
  • STM32 ADC基础知识讲解

    在正式的学习如何编写ADC代码时我们先来学习一下ADC的基础知识部分,只有掌握好了这些基础知识才能顺利的进行后面的代码编写。 ADC 指的是模数转换器(Analog-to-Digital Converter),它是一种用于将模拟信号转换为数字信号的电子设备或电路。 模拟信号是连续变化的信号,可

    2024年02月09日
    浏览(40)
  • YOLOv5基础知识入门(2)— YOLOv5核心基础知识讲解

    前言: Hello大家好,我是小哥谈。 YOLOV4出现之后不久,YOLOv5横空出世。YOLOv5在YOLOv4算法的基础上做了进一步的改进,使检测性能得到更进一步的提升。YOLOv5算法作为目前工业界使用的最普遍的检测算法,存在着很多可以学习的地方。本文将对YOLOv5检测算法的核心基础知识进行

    2024年02月14日
    浏览(50)
  • UE5 Niagara基础知识讲解

    2023年08月27日
    浏览(54)
  • css 动画基础知识和案例

      想要更好的掌握知识,可以常识将知识教授出来。这就是写这篇文章的目的。     animation:创建动画的意思;其中的属性有:animation:属性,执行时间 显示方式 执行次数。    animation: 执行动画名称 执行时间(50s 代表50s执行一个循环) 执行速度(linear 代表匀速) 重复次数

    2024年04月25日
    浏览(44)
  • MyBatis基础知识和快速入门、MyBatis核心配置文件讲解

    什么是Mybatis MyBatis 是一个优秀的基于java的 持久层框架 ,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。 mybatis通过xml或注解的方式将要执行的各种 statement配置起来,并通过java对象和statement中

    2024年02月04日
    浏览(101)
  • 【01】基础知识:React简介与案例

    React 概述 React 是一个将数据渲染为 HTML 视图 的开源 JavaScript 库 React 由 FaceBook 开发,且开源 为什么要学习 React 1、原生 JavaScript 操作 DOM 繁琐、效率低(使用 DOM-API 操作 UI) 2、使用 JavaScript 直接操作 DOM,浏览器会进行大量的重绘重排 3、原生 JavaScript 没有组件化编码方案,

    2024年02月07日
    浏览(54)
  • Tomcat和Servlet基础知识的讲解(JavaEE初阶系列16)

    目录 前言: 1.Tomcat 1.1Tomcat是什么 1.2下载安装 2.Servlet 2.1什么是Servlet 2.2使用Servlet来编写一个“hello world” 1.2.1创建项目(Maven) 1.2.2引入依赖(Servlet) 1.2.3创建目录(webapp) 1.2.4编写代码(HelloServlet) 1.2.5打包(war) 1.2.6部署(拷贝war到webapps目录中) 1.2.7验证(浏览器发一

    2024年02月11日
    浏览(43)
  • Nodejs后端架构基础知识和案例展示

    入门笔记,大神请绕路!!! 简单的说 Node.js 就是运行在服务端的 JavaScript。 Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。 Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。 优点: 1.高并发 (高并发的

    2023年04月11日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包