最简单的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的基础用法,希望大家可以从中收获一些什么。

相关推荐
布列瑟农的星空9 分钟前
大话设计模式——关注点分离原则下的事件处理
前端·后端·架构
yvvvy28 分钟前
前端必懂的 Cache 缓存机制详解
前端
北海几经夏44 分钟前
React自定义Hook
前端·react.js
龙在天1 小时前
从代码到屏幕,浏览器渲染网页做了什么❓
前端
TimelessHaze1 小时前
【performance面试考点】让面试官眼前一亮的performance性能优化
前端·性能优化·trae
yes or ok1 小时前
前端工程师面试题-vue
前端·javascript·vue.js
我要成为前端高手1 小时前
给不支持摇树的三方库(phaser) tree-shake?
前端·javascript
Noxi_lumors2 小时前
VITE BALABALA require balabla not supported
前端·vite
周胜22 小时前
node-sass
前端
aloha_2 小时前
Windows 系统中,杀死占用某个端口(如 8080)的进程
前端