最简单的Promise基础教程

我不敢对你保证,玫瑰花她会一直盛开

今天晚上月亮会不会在,丘比特什么时候才会到来

我不敢对你保证,我能一直富有我能一直年轻

一直拥有魔力充满活力

不管遇到什么难题 我都能够一直开心

为什么需要Promise

众所周知,JavaScript是单线程的,不像其他语言拥有多线程解决问题的能力。那么在JavaScript中遇到需求大,任务多的任务时,造成了进程堵塞。怎么样才能在不影响其他任务的情况下完成呢?

为了应对这类问题,JavaScript出现了 同步执行(Synchronous)和异步执行(Asynchronous) 这两个概念。

同步执行是指程序按照代码编写的顺序依次执行每个任务,一个任务必须等待前一个任务完成之后才能开始;而异步执行允许程序在等待某个任务完成的同时继续执行其他任务,从而不阻塞程序的运行流程。

而Promise则诞生于异步执行这个环境, 是一种用于处理异步操作的对象。它们提供了一种更清晰、更可控的方式来管理异步代码,解决了传统的回调函数(callback)可能带来的"回调地狱"(Callback Hell)问题,即嵌套的回调函数过多导致代码难以阅读和维护。

什么是Promise

简单来说,Promise 是 JavaScript 中用于处理异步操作的对象,它代表了一个异步操作的最终完成(或失败)及其结果值。 Promise 让异步变同步 提供了完善解决异步任务的机制

除此之外,我们可以说Promise是一个类,这个说法可能具有争议,因为Promise分明是函数和对象结合的一种抽象概念。那我为什么说他是个类呢?因为Promise具有丰富的类的特性。让我们来看这一串代码

typescript 复制代码
const p = new Promise((resolve,reject) => {  //executor
   console.log('333') //同步任务
 setTimeout(() => { // 异步任务 event loop
   console.log('222')
   resolve('Promise真好')
 }, 1000);
})
.then((data) => {
   // 等到executor 异步任务执行完后, 再执行then里面的函数
 console.log('111')
 console.log(data)
})
.catch(()=>{
console.log('error')
})

我们可以看到,可以new一个Promise出来,有内置的.then,.catch实例方法,除此之外,还有静态方法,Promise.all,Promise.race等,这些都是具有类属性的特质,都可以用于处理异步执行的结果。

让我们再加console.log(p.proto) 运行得到:

Promise运行机制

让我们再关注一下程序的运行结果:

我们应该都知道异步操作的执行原理,所以我们可以明白为什么333输出最早,后面的输出顺序则让人有点看不懂了,为什么会这样呢?

我们要先了解一个概念,executor执行器,也就是我们new出来的Promise,他会立即执行。

Promise有三个状态,分别是pending(等待),fulfilled(成功), rejected(失败) 怎样进行状态的切换呢?

就要向实例化对象new Promise()的括号中给两个函数参数了,分别为(resolve和reject),如果没有这两个函数参数,Promise的状态就不会改变,一直处于pending状态。

当程序开始执行时,executor立即执行333,随后遇到定时器这个异步操作,再执行完222之后,回调函数resolve被执行。同时Promise状态由pending变成fulfillled,再executor中的任务执行完后,触发Promise中的.then的回调函数,再输出111和Promise真好。

Promise 状态只会从pending 切换到 fulfilled 或者 rejected , 状态一旦确定, 就不会再变了。

Promise.all 和 Promise.race

Promise.all和Promise.race是Promise中非常有用的两个静态方法

Promise.all

先说Promise.all。它接受一个可迭代对象(如数组)作为参数,这个可迭代对象中的每个元素都应该是一个 Promise 或者是可以解析为 Promise 的值。Promise.all 会返回一个新的 Promise。在所有promise都成功的情况下才会成功,相反的,有一个失败就会全部失败。有了这个方法,可以让我们同时处理多个异步操作,大大增加了我们的工作效率。看几行代码加深印象:

ini 复制代码
const promise1 = Promise.resolve(3);
const promise2 = 42; // 不是Promise,但会被Promise.resolve自动转换
const promise3 = new Promise((resolve, reject) => {
        setTimeout(resolve, 100, 'foo');
}); 
Promise.all([promise1, promise2, promise3]).then(values => {
      console.log(values); // 输出: [3, 42, "foo"]
});
typescript 复制代码
const promise1 = Promise.resolve('Success');
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'Error'));
const promise3 = new Promise((resolve, reject) => setTimeout(resolve, 200, 'Third')); 
Promise.all([promise1, promise2, promise3]) .then(values => {
console.log(values); // 这个不会被执行 }) 
.catch(error => {
console.log(error); // 输出: Error
});

下面的因为promise2被拒绝,其余两个即使成功也不会运行

Promise.race

这个和Promise.all有些相似,都是接受一个可迭代对象(如数组)作为参数。与 Promise.all 不同,Promise.race 会在输入的 Promise 中的第一个被解析或拒绝的 Promise 完成时立即完成,而不会等待所有的 Promise 都完成,让我们分析下面代码:

javascript 复制代码
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
}); 
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then(value => {
console.log(value); // 输出: "two" });

在这个例子中,promise2promise1 更快地解析,因此 Promise.race 返回的 Promise 会以 promise2 的结果 "two" 来解析。

让我们再来看一个失败的案例:

typescript 复制代码
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
}); 
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, 'Error');
}); 
Promise.race([promise1, promise2])
.then(value => {
console.log(value); // 这个不会被执行
}) 
.catch(error => {
console.log(error);// 输出: Error
});

在这个例子中,尽管 promise1 最终会成功解析,但由于 promise2Promise1执行之前被拒绝,所以整个 Promise.race 会立即被拒绝,并输出 Error

注意:

如果所有传入的 Promise 都没有完成,那么 Promise.race 返回的 Promise 也不会完成。例如,如果所有的 Promise 都是永远挂起(pending)的状态,那么 Promise.race 也会保持挂起状态。 )。

这就是Promise的基础用法,希望大家可以从中收获一些什么。

相关推荐
鸿蒙场景化示例代码技术工程师11 分钟前
基于AssetStoreKit实现免密登录鸿蒙示例代码
前端
在掘金12 分钟前
【kk-utils】Excel工具——excel-js
前端·excel
Danny_FD14 分钟前
Canvas的应用与实践
前端·javascript
_请输入用户名16 分钟前
husky 切换 simlple-git-hook 失效解决方法
前端
前端九哥17 分钟前
🚀Vue 3 hooks 每次使用都是新建一个实例?一文彻底搞懂!🎉
前端·vue.js
盏灯17 分钟前
尤雨溪搞响应式为什么要从 Object.defineProperty 换成 Proxy❓
前端·vue.js
爱上大树的小猪17 分钟前
【前端样式】使用CSS Grid打造完美响应式卡片布局:auto-fill与minmax深度指南
前端·css·面试
代码小学僧17 分钟前
🤗 赛博佛祖 Cloudflare 初体验托管自定义域名与无限邮箱注册
前端·serverless·云计算
晴殇i18 分钟前
一行代码解决深拷贝问题,JavaScript新特性解析
前端
天天扭码28 分钟前
零基础入门 | 超详细讲解 | 小白也能看懂的爬虫程序——爬取微博热搜榜
前端·爬虫·cursor