Who is a Promise?

前世今生:

Promise 在 ECMAScript 2015( ES6 )中发布,在 ES6 发布之前,Promise是由 Jesse MacFadyen 在 2008 年提出的。他在一篇名为《Promise/A+》的文章中提出了 Promise 的规范草案,后来被业界广泛的应用。

后来在 ES6 的开发中, ECMAScript 标准委员会(ECMA International)将这一规范纳入了 ES6 的标准中。

本篇文章的任务:

  1. 理解Promise A+规范的基本概念
  2. 学会创建Promise
  3. 学会针对Promise进行后续处理

戴夫的烦恼

这里我们引用了袁教头在解释Promise这一东东时所用的案例

戴夫心中有很多女神,他今天下定决心,要向这些女神表白,他认为,只要女神够多,根据概率学原理,总有一个会接收他

为了稳妥起见,戴夫就决定使用串行的方式进行表白:先给第1位女神发送短信,然后等待女神的回应,如果成功了,就结束,如果失败了,则再给第2位女神发送短信,依次类推,我们用图来解释

image-20210618150543263

戴夫的女神一共有4位,名字分别是:坚果、豌豆射手、雪花豌豆、小海豚

发短信是一个重复性的劳动,但是戴夫他是个程序员,因此决定用函数封装来完成这个体力活

/**
 * 像某位女神发送一则表白信
 * @param {*} name 女神的姓名
 * @param {*} onFulffiled 成功后的回调
 * @param {*} onRejected 失败后的回调
 */
function sendMessage(name, onFulffiled, onRejected) {
    console.log(`戴夫 -> ${name}: 我不知道未来会怎样,但我知道我想和你一起经历。你愿意和我一起探索未知吗?`)
    
    console.log(`等待${name}的回复`)
    
    // 模拟 女神回复需要一定的时间
    setTimeout(() => {
        // 模拟 有10%的几率成功
        if (Math.random() <= 0.1) {
          // 成功,调用 onFuffiled,并传递女神的回复
          onFulffiled(`${name} -> 戴夫:我愿意😘`);
        } else {
          // 失败,调用 onRejected,并传递女神的回复
          onRejected(`${name} -> 戴夫:你是个好人😜`);
        }
    }, 1000)
}

有了这个函数之后,戴夫就开始写程序给每个女神发短信了

// 首先 戴夫 先跟坚果发送了短信
sendMessage(
  "坚果",
  (reply) => {
    // 如果成功了,输出回复的消息
    console.log(reply);
  },
  (reply) => {
    // 失败了,输出回复的消息后,向 豌豆射手 发送消息
    console.log(reply);
    sendMessage(
      "豌豆射手",
      (reply) => {
        // 如果成功了,输出回复的消息
        console.log(reply);
      },
      (reply) => {
        // 如果失败了,输出回复的消息, 向 雪花豌豆 发送消息
        console.log(reply);
        sendMessage(
          "雪花豌豆",
          (reply) => {
            // 成功了,输出回复的消息
            console.log(reply);
          },
          (reply) => {
            // 如果失败了,输出回复的消息, 向 小海豚 发送消息
            console.log(reply);
            sendMessage(
              "小海豚",
              (reply) => {
              	// 成功了,输出回复的消息 结束
                console.log(reply);
              },
              (reply) => {
                // 如果还是失败了,戴夫将要孤独终老了
                console.log(reply);
                console.log("戴夫的女神,都嫌弃戴夫没修胡子,把戴夫都拒绝了");
              }
            );
          }
        );
      }
    );
  }
);

戴夫把程序写完之后,分享给了他的朋友看,戴夫的朋友是一个完美主义者,他看完之后的内心时崩溃的。

在这一层有一层的回调中,犹如托塔李天王的玲珑塔一般,所以,就形成了 传说中的「回调地狱 callback hell」。

那我们需要如何去解决,这一座宝塔呢?

这就要用到了 Promise

Promise规范

在MDN中是这样解释的, 他将Promise 比作一个代理,用来代表一个在创建 promise 时不一定已知的值。它允许你将处理程序与异步操作的最终成功值或失败原因关联起来。这使得异步方法可以像同步方法一样有返回值:异步方法不会立即返回最终值,而是返回一个 promise,以便在将来的某个时间点提供该值。

但在我的理解中,Promise是一套专门处理异步场景的规范,它能有效的避免回调地狱的产生,使异步代码更加清晰、简洁、统一

这套规范最早诞生于前端社区,由 Jesse MacFadyen 在 2008 年提出,规范名称为Promise A+

该规范出现后,立即得到了业界很多开发者的响应

Promise A+ 规定

  1. 所有的异步场景,都可以看作是一个异步任务,每个异步任务,在 JS 中应该表现为一个对象,该对象称之为Promise对象,也叫做任务对象在这里插入图片描述

  2. 每个 Promise 对象都会有3个状态

    在这里插入图片描述

    我们将上面的图简化一下:

    在这里插入图片描述

    Promise 的逻辑关系:

    • 总是由未决状态变为已决状态,无法逆行
    • 任务总会从挂起(pending)到完成(fulfilled)或失败(rejected),在已决状态中也只会由完成跟失败。无法逆行
    • 在任务执行完毕之后,也就是确定为完成或失败的一种,任务就不会返回去重新执行;任务状态就永远无法改变。
  3. Promise 任务由挂起 -> 完成称为 resolve;由挂起 -> 失败 称为 reject。在任务的执行中,不管是 成功还是失败他都允许你携带一个形参。任务完成时可能有一个相关的数据,任务失败时,可能是一个失败的原因。

在这里插入图片描述

  1. Promise 的 Thenable 接口,该接口允许我们针对任务进行后续的操作,在针对完成状态进行的后续操作称为onFulfilled,对于失败状态的后续操作称为onRejected

在这里插入图片描述

Promise Api

在ES6中,ECMAScript 标准委员会为我们实现了一整套的API,用来帮助我们实现 Promise 的A+规范

Promise 构造函数

Promise 构造函数接受一个执行器函数作为参数,该函数接受两个参数:resolverejectresolvereject 是两个函数,用于改变 Promise 的状态。

const promise = new Promise((resolve, reject) => {
    // 异步操作
    setTimeout(() => {
        const success = true;
        if (success) {
            resolve('Operation successful');
        } else {
            reject('Operation failed');
        }
    }, 1000);
});

Promise 方法

1. .then()

.then() 方法接受两个回调函数作为参数:第一个回调函数在 Promise 被 resolve 时调用,第二个回调函数在 Promise 被 reject 时调用(可选)。

promise
    .then(result => console.log(result))
    .catch(error => console.error(error));
2. .catch()

.catch() 方法用于处理 Promise 被 reject 时产生的错误。

promise
    .then(result => console.log(result))
    .catch(error => console.error(error));
3. .finally()

.finally() 方法用于无论 Promise 的结果如何都会执行的回调函数。

promise
    .then(result => console.log(result))
    .catch(error => console.error(error))
    .finally(() => console.log('Finally, the operation is complete'));

静态方法

1. Promise.resolve()

Promise.resolve() 方法用于立即创建一个已解决的 Promise。

const immediateSuccess = Promise.resolve('Immediate success');
immediateSuccess.then(result => console.log(result));
2. Promise.reject()

Promise.reject() 方法用于立即创建一个已拒绝的 Promise。

const immediateFailure = Promise.reject('Immediate failure');
immediateFailure.catch(error => console.error(error));
3. Promise.all()

Promise.all() 方法用于等待所有的 Promise 都完成(resolve)。

const promises = [
    fetch('https://api.example.com/data1'),
    fetch('https://api.example.com/data2')
];

Promise.all(promises)
    .then(responses => Promise.all(responses.map(r => r.json())))
    .then(results => console.log(results))
    .catch(error => console.error('Error fetching data:', error));
4. Promise.allSettled()

Promise.allSettled() 方法用于等待所有的 Promise 都完成,无论它们是 resolved 还是 rejected。

const promises = [
    fetch('https://api.example.com/data1'),
    fetch('https://api.example.com/data2')
];

Promise.allSettled(promises)
    .then(results => {
        results.forEach(result => {
            if (result.status === 'fulfilled') {
                console.log('Fulfilled:', result.value);
            } else {
                console.error('Rejected:', result.reason);
            }
        });
    });
5. Promise.race()

Promise.race() 方法用于等待第一个完成的 Promise。

const promises = [
    fetch('https://api.example.com/data1'),
    fetch('https://api.example.com/data2')
];

Promise.race(promises)
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error('Error fetching data:', error));

异步函数 (async/await)

async/await 是基于 Promise 的一种更简洁的写法,它可以使异步代码看起来更像同步代码。

async function fetchData() {
    try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        console.log(data);
    } catch (error) {
        console.error('Error fetching data:', error);
    }
}

fetchData();
  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值