我不敢对你保证,玫瑰花她会一直盛开
今天晚上月亮会不会在,丘比特什么时候才会到来
我不敢对你保证,我能一直富有我能一直年轻
一直拥有魔力充满活力
不管遇到什么难题 我都能够一直开心
为什么需要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" });
在这个例子中,promise2
比 promise1
更快地解析,因此 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
最终会成功解析,但由于 promise2
在Promise1
执行之前被拒绝,所以整个 Promise.race
会立即被拒绝,并输出 Error
。
注意:
如果所有传入的 Promise
都没有完成,那么 Promise.race
返回的 Promise
也不会完成。例如,如果所有的 Promise
都是永远挂起(pending)的状态,那么 Promise.race
也会保持挂起状态。 )。
这就是Promise的基础用法,希望大家可以从中收获一些什么。