Promise的用法及案列

news2024/10/6 19:19:57

Promise:异步编程的优雅解决方案

在JavaScript中,异步编程是处理耗时操作(如网络请求、文件读取等)的重要手段。传统的异步编程方式(如回调函数)往往会导致“回调地狱”问题,使得代码结构混乱、难以维护。为了解决这一问题,ES6引入了Promise对象,提供了一种更加优雅、可读性更高的异步编程模式。

一、Promise的基本概念

Promise是一个构造函数,用于创建表示异步操作的对象。Promise对象有三种状态:Pending(进行中)、Resolved(已完成)、Rejected(已失败)。当Promise被创建时,它处于Pending状态。通过调用resolve方法,可以将Promise的状态更改为Resolved,并传递一个结果值;通过调用reject方法,可以将Promise的状态更改为Rejected,并传递一个错误信息。

二、Promise的用法

  1. 创建Promise对象

    使用new Promise(executor)语法创建Promise对象,其中executor是一个接受两个参数的函数:resolvereject。这两个参数也是函数,分别用于将Promise的状态更改为Resolved和Rejected。

    const promise = new Promise((resolve, reject) => {
        // 异步操作
        if (/* 操作成功 */) {
            resolve('成功的结果');
        } else {
            reject('失败的原因');
        }
    });
    
  2. 处理Promise结果

    Promise对象提供了thencatch方法,用于处理成功和失败的情况。then方法接受两个参数:onFulfilled(成功时的回调函数)和onRejected(失败时的回调函数)。catch方法用于捕获Promise链中的错误。

    promise.then(
        (value) => {
            console.log('成功:', value);
        },
        (reason) => {
            console.error('失败:', reason);
        }
    ).catch((error) => {
        console.error('捕获到的错误:', error);
    });
    
  3. Promise链式调用

    Promise支持链式调用,即一个Promise对象的then方法可以返回一个新的Promise对象,从而可以继续调用then方法。这允许我们将多个异步操作串联起来,形成一个清晰的异步流程。

    const firstPromise = new Promise((resolve) => {
        setTimeout(() => resolve('第一个操作成功'), 1000);
    });
    
    const secondPromise = firstPromise.then((value) => {
        console.log(value);
        return new Promise((resolve) => {
            setTimeout(() => resolve('第二个操作成功'), 1000);
        });
    });
    
    secondPromise.then((value) => {
        console.log(value);
    });
    
  4. Promise静态方法

    Promise还提供了几个静态方法,用于创建和处理Promise对象:

    • Promise.all(iterable):接受一个可迭代对象(如数组),返回一个新的Promise对象,该对象在所有给定的Promise对象都成功时才会成功,任何一个失败都会导致整个Promise对象失败。
    • Promise.race(iterable):接受一个可迭代对象,返回一个新的Promise对象,该对象的状态由第一个完成的Promise对象决定(无论是成功还是失败)。
    • Promise.resolve(value):返回一个以给定值解析的Promise对象。
    • Promise.reject(reason):返回一个以给定原因拒绝的Promise对象。

三、Promise的创作流程

  1. 定义Promise构造函数

    创建一个类(或构造函数),用于生成Promise对象。在该构造函数中,定义状态(Pending、Resolved、Rejected)和存储结果或错误信息的变量。同时,定义resolvereject方法,用于更改状态和存储结果或错误信息。

    class MyPromise {
        constructor(fn) {
            this._status = 'pending';
            this._value = undefined;
            const resolve = (value) => {
                if (this._status === 'pending') {
                    this._status = 'fulfilled';
                    this._value = value;
                }
            };
            const reject = (reason) => {
                if (this._status === 'pending') {
                    this._status = 'rejected';
                    this._value = reason;
                }
            };
            try {
                fn(resolve, reject);
            } catch (error) {
                reject(error);
            }
        }
    
        then(onFulfilled, onRejected) {
            if (this._status === 'fulfilled' && onFulfilled) {
                onFulfilled(this._value);
            }
            if (this._status === 'rejected' && onRejected) {
                onRejected(this._value);
            }
        }
    }
    
  2. 实现then方法

    在Promise类中实现then方法,该方法接受两个参数:成功时的回调函数和失败时的回调函数。根据Promise的当前状态,调用相应的回调函数,并传递结果或错误信息。

    // 在MyPromise类中实现的then方法(见上)
    
  3. 使用Promise对象

    使用new MyPromise(executor)语法创建MyPromise对象,并在executor函数中执行异步操作。通过调用then方法处理成功和失败的情况。

    const myPromise = new MyPromise((resolve, reject) => {
        setTimeout(() => {
            const success = true; // 模拟异步操作的成功或失败
            if (success) {
                resolve('异步操作成功');
            } else {
                reject('异步操作失败');
            }
        }, 1000);
    });
    
    myPromise.then(
        (value) => {
            console.log('成功:', value);
        },
        (reason) => {
            console.error('失败:', reason);
        }
    );
    

以下是一些关于Promise的实际案例,涵盖了JavaScript中Promise的不同使用场景:

四、基本使用案例

  1. 异步请求的链式处理

    • 场景描述:在处理网络请求时,经常需要按照特定的顺序执行多个异步操作。
    • 示例代码:
    function fetchData(url) {
    	return new Promise((resolve, reject) => {
    		// 模拟网络请求
    		setTimeout(() => {
    			resolve("数据加载完成");
    			// 或者 reject("请求失败");
    		}, 1000);
    	});
    }
    
    fetchData("http://example.com/data")
    	.then(response => {
    		console.log(response);
    		return fetchData("http://example.com/more-data");
    	})
    	.then(moreResponse => {
    		console.log(moreResponse);
    	})
    	.catch(error => {
    		console.error("请求出错:", error);
    	});
    
  2. 文件读取

    • 场景描述:在Node.js环境中,读取文件是一个常见的异步操作。
    • 示例代码(假设使用fs模块):
    const fs = require('fs').promises;
    
    fs.readFile('example.txt', 'utf-8')
    	.then(data => {
    		console.log("文件内容:", data);
    	})
    	.catch(error => {
    		console.error("读取文件出错:", error);
    	});
    

五、高级使用案例

  1. Promise.race实现请求超时处理

    • 场景描述:在发送请求时,如果请求在一定时间内没有响应,则视为请求超时。
    • 示例代码:
    const p1 = fetchData("http://example.com/slow-data");
    const p2 = new Promise((_, reject) => {
    	setTimeout(() => reject(new Error("请求超时")), 3000);
    });
    
    Promise.race([p1, p2])
    	.then(response => {
    		console.log(response);
    	})
    	.catch(error => {
    		console.error("请求出错或超时:", error);
    	});
    
  2. Promise.all用于并行处理多个请求

    • 场景描述:有时需要同时发送多个请求,并等待所有请求都完成后才进行下一步操作。
    • 示例代码:
    const requests = [
    	fetchData("http://example.com/data1"),
    	fetchData("http://example.com/data2"),
    	fetchData("http://example.com/data3")
    ];
    
    Promise.all(requests)
    	.then(responses => {
    		responses.forEach(response => {
    			console.log(response);
    		});
    	})
    	.catch(error => {
    		console.error("其中一个请求出错:", error);
    	});
    
  3. Promise的重试机制

    • 场景描述:在某些情况下,如果请求失败,可能需要进行重试。
    • 示例代码:
    function retryFetchData(url, times = 3, delay = 1000) {
    	return new Promise((resolve, reject) => {
    		function attempt() {
    			fetchData(url)
    				.then(resolve)
    				.catch(error => {
    					if (times > 1) {
    						console.log(`还有${times - 1}次尝试`);
    						setTimeout(attempt, delay);
    					} else {
    						reject(error);
    					}
    				});
    		}
    
    		attempt();
    	});
    }
    
    retryFetchData("http://example.com/unreliable-data")
    	.then(response => {
    		console.log(response);
    	})
    	.catch(error => {
    		console.error("请求失败,重试后仍然出错:", error);
    	});
    

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

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

相关文章

SpringIoC容器的初识

一、SpringIoC容器的介绍 Spring IoC 容器,负责实例化、配置和组装 bean(组件)。容器通过读取配置元数据来获取有关要实例化、配置和组装组件的指令。配置元数据以 XML、Java 注解或 Java 代码形式表现。它允许表达组成应用程序的组件以及这…

Vueron引领未来出行:2026年ADAS激光雷达解决方案上市路线图深度剖析

Vueron ADAS激光雷达解决方案路线图分析:2026年上市展望 Vueron近期发布的ADAS激光雷达解决方案路线图,标志着该公司在自动驾驶技术领域迈出了重要一步。该路线图以2026年上市为目标,彰显了Vueron对未来市场趋势的精准把握和对技术创新的坚定…

如何实现 C/C++ 与 Python 的通信?

在现代编程中,C/C与Python的通信已经成为一种趋势,尤其是在需要高性能和灵活性的场景中。本文将深入探讨如何实现这两者之间的互通,包括基础和高级方法,帮助大家在混合编程中游刃有余。 C/C 调用 Python(基础篇&#…

AI 时代:产品经理不“AI”就出局?

即便你没想去做“AI 产品经理”,那你也不能成为一个不会用 AI 的产品经理。 产品经理肯定是所有互联网从业者中,最先捕捉到 AI 趋势的岗位。 但只知道 AI、关注 AI 还不够,仔细审视一下:你自己的工作,被 AI 提效了么…

打造自己的RAG解析大模型:Windows部署OCR服务(可商业应用)

在上一篇文章中,我们介绍了如何在 Windows 环境中配置 OCR 相关模型,并完成了模型验证。本篇文章将基于之前的内容,进一步讲解如何将文本检测、方向分类和文本识别模型进行串联,最终搭建一个基础的 OCR 应用服务。通过这些模型的串…

wxml语法-声明和绑定数据

文章目录 1、展示内容1.1、{{school}} 直接引用的是一个字符串或其他类型的简单值1.1.1、index.wxml1.1.2、index.js 1.2、{{obj.name}} 引用的是一个对象中的特定属性值1.2.1、index.wxml1.2.2、index.js 2、绑定属性值2.1、使用数据绑定的方式来动态设置元素的属性值2.1.1、i…

冯诺依曼体系|操作系统

目录 一、硬件:冯诺依曼体系 1.冯诺依曼体系结构 2.冯诺依曼体系结构组成 3.内存的重要性 (1)提升运行速度 (2)提升运行效率 二、软件:操作系统 1.什么是操作系统 (1)内部理…

代码随想录Day54

今天是国庆假期后的恢复做题的第一天,摆了那么久感觉还是有点没摆够哈哈哈哈!今天两道题都是困难题,两道题都去看讲解了,感觉这两道题是高度相似的,接雨水用单调递增栈来做,柱状图中最大的矩形用单调递减栈…

水凝胶发生器,不对称设计妙,医电应用前景广

大家好!今天来了解一种具有工程机械离子不对称性的水凝胶发生器——《A high-current hydrogel generator with engineered mechanoionic asymmetry》发表于《Nature Communications》。嘿!你能想象一种材料,它能像魔法一样在低频运动下产生高…

消息称苹果iPhone系列将完全放弃LCD屏幕

近日,据日经亚洲消息,苹果公司将于明年初推出搭载OLED显示屏的 iPhone SE 4,标志其整个iPhone系列已进入从 LCD 过渡到 OLED 技术的最后阶段,2025年及之后销售的所有iPhone机型均将搭载OLED屏幕。 由此,两家日本面板供…

【一起学NLP】Chapter3-使用神经网络解决问题

目录 使用神经网络解决问题Tip:数据集划分学习使用的代码Tip:epochTip:数据打乱Trainer类Tip-高速化计算 使用神经网络解决问题 import sys sys.path.append(..) # 为了引入父目录的文件而进行的设定 from dataset import spiral import matplotlib.pyplot as pltx,t spiral.…

解决银河麒麟桌面操作系统V10(ARM)中`apt-get update`“正在等待报头”问题

解决银河麒麟桌面操作系统V10(ARM)中apt-get update“正在等待报头”问题 1、问题描述2、 解决方法步骤一:打开终端步骤二:清理APT缓存步骤三:再次尝试更新软件源 💖The Begin💖点点关注&#x…

利士策分享,故事创作和造谣及假新闻之间如何界定?

利士策分享,故事创作和造谣及假新闻之间如何界定? 在这个信息爆炸的时代,一篇打着“人民网”旗号的虚假文章《低俗炒作博眼球,曝"瓜"文化不可取》在网络上迅速发酵,不仅误导了公众,更对无辜者造…

【源码+文档】基于SpringBoot+Vue校园智慧迎新服务平台

🚩如何选题? 如何选题、让题目的难度在可控范围,以及如何在选题过程以及整个毕设过程中如何与老师沟通,这些问题是需要大家在选题前需要考虑的,具体的方法我会在文末详细为你解答。 🚭如何快速熟悉一个项目…

MySQL【知识改变命运】03

表的基本操作 1:查看所有表2:创建表3:查看表结构4:修改表5: 删除表 前言:我们先了解一个知识: MySQL安装后会有MySQL服务——管理多个库——每个库管理多个表——每个表管理多行数据——数据行由…

《Windows PE》4.1导入表

导入表顾名思义,就是记录外部导入函数信息的表。这些信息包括外部导入函数的序号、名称、地址和所属的DLL动态链接库的名称。Windows程序中使用的所有API接口函数都是从系统DLL中调用的。当然也可能是自定义的DLL动态链接库。对于调用方,我们称之为导入函…

本田汽车投资SiLC Technologies:携手共促自动驾驶技术新飞跃

SiLC Technologies获本田汽车投资:加速自动驾驶技术革新 近日,硅谷光子学初创公司SiLC Technologies宣布获得本田汽车的投资,这一合作标志着双方将共同推进自动驾驶技术领域的革新与发展。本田此次投资不仅体现了对SiLC Technologies技术实力的认可,也彰显了本田在自动驾驶…

进程管理和进程调度的基本过程(详细版)

“无论你走得多慢,总比停下来要好。” 对于操作系统内核来说,里面包含的功能是非常多的,其中有一个功能和日常开发,息息相关。 进程管理: 进程(process/task):进程就是正在执行的应…

一个月学会Java 第4天 运算符和数据转换

Day4 运算符和数据转换 今天来讲运算符,每个运算符的作用和现象,首先我们先复习一下数据类型, day2讲过基本数据类型有八种,int、short、long、byte、char、boolean、float、double,分别为四个整型、一个字符型、一个布…

代码随想录 | Day28 | 回溯算法:组合组合总和III

代码随想录 | Day28 | 回溯算法:组合&&组合总和III 关于这个章节,大家最好是对递归函数的理解要比较到位,听着b站视频课可能呢才舒服点,可以先去搜一搜关于递归函数的讲解,理解,再开始这个章节会比…