人人都能搞懂的Promise(一)

1.逐步了解promise

根据官方描述总结,promise是ES6新出的语法,是一个内置的构造函数,用于解决异步问题的一种方案;
既然是内置的构造函数,那我们看看打印出来是个什么东西

console.dir(Promise)

控制台结果:在这里插入图片描述
可以看到,promise这个构造函数上有很多方法(如all,race,reject,resolve…);他的原型上,也就是红色部分区域也有我们常用的方法(then,catch…);既然如此,那就new出来看看实例上是什么

    const p = new Promise((resvole,reject)=>{
    
    })
    console.dir(p)
    console.log(Object.prototype.toString.call(p),'1111111') //[object Promise] 1111111

控制台结果:
在这里插入图片描述
看到这里,继续总结一下就是:
一个promise的实例对象,拥有一个PromiseState属性来记录自身的状态,还有一个PromiseResult属性用来记录收到的结果;当然还有刚刚原型上的一些方法(then,catch…),所以我们new出来的p实例是可以进行.then方法的; 相信到这里,大家对promise有了一个初步的认识,也对此有些许疑问。

比如,状态是用来干嘛的?记录的结果又有什么用?我们接着往下。

状态

下面是promise的简单用法与官网流程图
简单用法:
// 代码块1
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
  	if(成功){
  		resolve('成功数据');
  	}else{
  		reject('失败原因')
  	}
  }, 300);
});

//代码块2
//下述 then方法中函数A代表第一个参数,函数B代表第二个参数
p.then((value) => {
  console.log(value);
},(reason) => {
  console.log(reason);
},);

代码块1

创建一个promise的实例 p ,他初始处于pending(等待)状态,什么时候会改变状态呢 ?
resolve 函数执行的时候,状态即改变成了fulfill(成功)状态;同样,如果执行的是 reject 函数,则状态就会改变成reject(失败)状态;那执行完 resolve,reject 后状态是改变了,那改变后该执行的函数要写在哪呢?这就是promise的精髓所在。这时候就需要使用到 .then 方法了

代码块2

.then 方法接收两个参数,两个参数都是函数,第一个参数A函数代表的是状态为成功时执行的,第二个参数B函数代表状态为失败时执行的;最神奇的便是 .then 方法返回结果一定是一个Promise实例,仍然可以进行链式调用.then方法

根据代码可以看到,Promise接收一个函数作为参数,语法:let p = new Promise(executor); p为promise的实例对象,executor叫做执行器函数,这个executor会立即执行且接收两个参数,这两个参数都是函数;拆解一下就是

let p1 = new Promise(executor)

function executor(a,b){
	console.log('立即执行')
	// 这里做改变状态的操作,可以在异步任务的回调里改变,也可以同步改变
	// 想将P1等待状态 改成 成功状态 的时候执行a()
	if(成功){
		a()
	}else{
	// 想将p1 等待状态 改成 失败状态 的时候执行b()
		b()
	}
}
流程图:

在这里插入图片描述
结合代码与流程图,我们继续总结一下:

1. 一个promise对象必定处于三个状态中的其中一个(pending:等待中,fulfill:成功了,reject:失败了)。

2. Promise的状态不可逆,且一个promise对象只能改变一次状态,只能由pending转换成fulfill,或者pending转换成reject。

3. 改变状态后执行的函数:
如果是成功的状态:执行.then方法中的传入第一个参数(函数A)
如果是失败的状态:(有两种方法)
3.1 执行.then方法中的传入第二个参数(函数B)
3.2 .执行.catch方法中传入的第一个参数(函数B)

所以状态是什么:

Promise的状态用于表示Promise当前所处的阶段,并决定后续的操作和回调函数的执行

实例上记录的结果

由代码1和代码2可以看出,通过调用resolve,reject函数来改变状态的时候可以传入参数,这个参数将会保存在promise实例的PromiseResult属性上,在实例进行 .then 或者 .catch 方法的时候可以取到该值;
我们习惯性的将执行成功函数A(res)接收的res叫做成功的结果数据value,
执行失败函数B(res)接收的res叫做失败的原因reason
在下文中统称为兑现值


看完上述内容,我相信您对promise有了一个基本的认识与使用,对下面方法的学习将会理解更加深刻。

2.Promise常用方法

1. Promise 构造函数: Promise (excutor) {}

创建一个promise实例,它允许你将处理程序与异步操作的最终成功值或失败原因关联起来。

代码示例:

const p = new Promise((resvole,reject)=>{
	setTimeout(() => {
		resvole('data')
	}
})

2.Promise.prototype.then 也就是实例p的.then方法

描述:

then方法用于为 Promise 对象的完成(成功或失败)设置回调函数。

then方法可以接受两个参数:
第一个参数是异步操作成功时的回调函数,
第二个参数是异步操作失败时的回调函数。   	
通常我们只会传递第一个参数,即成功时的回调函数。

成功回调函数接受异步操作的结果作为参数,可以在回调函数中对结果进行处理和操作。
这样可以保持异步操作的顺序性,确保每个操作都按照指定的顺序执行。

返回值:

1.返回一个新值:
	如果 onFulfilled 或 onRejected 返回一个非 Promise 值,then() 返回的新 Promise 会立即以
	这个值作为兑现值(fulfilled value)进入兑现状态。
	
2.返回 Promise:
	如果 onFulfilled 或 onRejected 返回一个 Promise 对象,then() 返回的新 Promise 会“跟随”
	这个返回的 Promise。
    这意味着新 Promise 的状态将取决于这个返回的 Promise 的状态:
	如果返回的 Promise 成功,新 Promise 也会以相同的值成功传递。
	如果返回的 Promise 拒绝,新 Promise 也会以相同的拒绝原因拒绝。
	如果返回的 Promise 本身是一个挂起(pending)状态,那么新 Promise 也会保持挂起状态,直
	到那个 Promise 兑现或拒绝。
	
3.抛出异常:
	如果 onFulfilled 或 onRejected 抛出一个错误,then() 返回的新 Promise 会立即以这个错误
	作为拒绝原因进入拒绝状态。
	
4.不返回任何值:
	如果 onFulfilled 或 onRejected 没有返回任何值,then() 返回的新 Promise 会以 undefined 
	作为兑现值,并立即进入兑现状态。在所有这些情况下,then() 方法总是返回一个新的 
	Promise 对象。这个新 Promise 的行为基于 onFulfilled 和 onRejected 处理函数的返回值或行为。
	这种设计允许 Promise 链的创建,每个 then() 调用都返回一个新的 Promise,使得你可以继续链接
	更多的处理函数。

总结一下

  1. then() 方法总是返回一个新的 Promise 对象
  2. 这个新 Promise 的行为基于处理函数的返回值。如果处理函数返回一个 Promise,新 Promise 会跟随那个 Promise 的状态;
  3. 如果处理函数返回一个非 Promise 值或抛出异常,新 Promise 会以那个值或异常作为兑现或拒绝的原因;
  4. 如果处理函数没有返回值,新 Promise 会以 undefined 作为兑现值。

代码示例:

const p = new Promise((resvole,reject)=>{
	resvole(1)
})

//then链式调用
p.then((value1)=>{
	console.log(value1) // 1
}).then((value2)=>{
	console.log(value2) // undefined 因为在第一个then方法中未return所以将undefined 作为兑现值。
});
//then抛出错误
Promise.resolve()
  .then(() => {
    // 令 .then() 返回一个被拒绝的 promise
    throw new Error("Oh no!");
  })
  .then(
    () => {
      console.log("不会被调用。");
    },
    (error) => {
      console.error(`onRejected 函数被调用:${error.message}`);
    },
  );
  //如果函数抛出错误或返回一个被拒绝的 Promise,则 then 返回的 Promise 最终将被拒绝。
  //所以打印的是:onRejected 函数被调用:Oh no!

3. Promise.prototype.catch 方法也就是实例p的.catch 方法

描述:

语法:catch(onRejected),接收一个处理失败状态的函数;来处理 Promise 被拒绝的情况。
也就是then()的语法糖, 相当于: then(undefined, onRejected) 

返回值:

1.返回一个新的 Promise:
如果 catch 函数内部返回了一个新的 Promise,那么 catch 方法返回的新 Promise 将会
“跟随”这个返回的 Promise。这意味着它会采用这个新 Promise 的最终状态(兑现或拒绝)和值。

promise.catch(error => {
  console.error(error);
  return new Promise((resolve, reject) => {
    resolve('Recovered value');
  });
}).then(value => {
  console.log(value); // 输出 "Recovered value"
});

2.返回一个值:
如果 catch 函数返回了一个非 Promise 值,那么 catch 方法返回的新 Promise 将以这个值作为
兑现值,并处于兑现状态。

promise.catch(error => {
  console.error(error);
  return 'Recovered value';
}).then(value => {
  console.log(value); // 输出 "Recovered value"
});

3.抛出错误:
如果 catch 函数内部抛出了一个错误,那么 catch 方法返回的新 Promise 会以这个错误作为拒绝值,
并处于拒绝状态。

promise.catch(error => {
  console.error(error);
  throw new Error('Another error occurred');
}).catch(newError => {
  console.error(newError); // 输出 "Another error occurred"
});

4.不返回任何值:
如果 catch 函数没有返回任何值(或者明确返回 undefined),那么 catch 方法返回的新 Promise 
也会以 undefined 作为兑现值,并处于兑现状态。

promise.catch(error => {
  console.error(error);
}).then(value => {
  console.log(value); // 输出 "undefined"
});

5.不处理错误:
如果 catch 方法没有被调用(即 Promise 被拒绝,但没有任何 catch 或 then 的拒绝处理器处理它),
那么 Promise 链将会中断,并且拒绝状态及其原因将会丢失。这通常是一个编程错误,应该避免。

总结一下
无论 catch 函数内部发生了什么,它总是返回一个新的 Promise 对象,这允许开发者继续链式调用 then 或 catch 方法来处理 Promise 的进一步状态。

代码示例:

// 1.大多数情况下,抛出错误会调用 catch() 方法:
const p1 = new Promise((resolve, reject) => {
  throw new Error("哦吼!");
});

p1.catch((e) => {
  console.error(e); // "哦吼!"
});

// 2.在异步函数内部抛出的错误会像未捕获的错误一样:
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    throw new Error("未捕获的异常!");
  }, 1000);
});

p2.catch((e) => {
  console.error(e); // 永远不会被调用
});

// 3.在调用 resolve 之后抛出的错误会被忽略:
const p3 = new Promise((resolve, reject) => {
  resolve();
  throw new Error("Silenced Exception!");
});

p3.catch((e) => {
  console.error(e); // 这里永远不会执行
});

4. Promise.resolve 方法

语法:Promise.resolve (value)
说明: 返回一个成功/失败的 promise 对象 
Promise.resolve()方法的具体行为如下:
如果参数为空或者不是Promise实例,则直接返回一个resolved状态的Promise对象。
如果参数是Promise实例,则不做任何修改,原封不动地返回这个实例。
如果参数是具有then方法的对象,则Promise.resolve()会将这个对象转为Promise对象,
并立即执行这个对象的then方法。

代码示例:

// 1.使用 Promise.resolve 静态方法
Promise.resolve("成功").then(
  (value) => {
    console.log(value); // "成功"
  },
  (reason) => {
    // 不会被调用
  },
);

// 2.resolve 一个数组
const p = Promise.resolve([1, 2, 3]);
p.then((v) => {
  console.log(v[0]); // 1
});

// 3.resolve 另一个 promise
// Promise.resolve() 方法会重用已存在的 Promise 实例。如果它正在解决一个原生的 Promise,
// 它将返回同一 Promise 实例,而不会创建一个封装对象。
const original = Promise.resolve(33);
const cast = Promise.resolve(original);
cast.then((value) => {
  console.log(`值:${value}`);
});
console.log(`original === cast ? ${original === cast}`);

// 按顺序打印:
// original === cast ? true
// 值:33

5. Promise.reject 方法

语法:Promise.reject(reason)
返回一个失败状态的(rejected)的 Promise,失败原因为给定的参数。

示例代码:

// 1.使用 Promise.reject() 静态方法
Promise.reject(new Error("失败")).then(
  () => {
    // 不会被调用
  },
  (error) => {
    console.error(error); // Stacktrace
  },
);
// 2.reject 一个 promise 对象
const p = Promise.resolve(1);
const rejected = Promise.reject(p);
console.log(rejected === p); // false
rejected.catch((v) => {
  console.log(v === p); // true
});

总结:
与 Promise.resolve 不同,Promise.reject 方法不会重用已存在的 Promise 实例。
它始终返回一个新的 Promise 实例,该实例封装了拒绝的原因(reason)。

6. Promise.all 方法

语法:Promise.all(iterable) 
iterable为可迭代的对象,一般为数组,这个方法接收一个数组,然后再以数组的形式返回
一般接收一个包含多个 Promise 对象的数组作为参数,并返回一个新的 Promise 对象,
这个新的 Promise 对象会在所有给定的 Promise 对象都兑现(fulfilled)后兑现,或者当任何
一个 Promise 对象被拒绝(rejected)时立即拒绝。

示例代码:

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
  // 输出: [3, 42, "foo"]
}).catch((error) => {
  console.error('An error occurred:', error);
});

// 如果 promise3 被拒绝,则会执行 catch 里的代码

总结:

  1. 等待多个 Promise:
    Promise.all() 允许你等待多个 Promise 同时完成。这对于并发执行多个异步操作并收集结果非常有用。

  2. 返回值:
    Promise.all() 返回一个新的 Promise,这个新的 Promise 在所有传入的 Promise 都成功兑现时,会以一个包含所有兑现值的数组作为其结果。如果任何一个 Promise 被拒绝,新的 Promise 会立即以第一个被拒绝的 Promise 的拒绝原因作为其结果。

  3. 结果顺序:
    Promise.all() 保证返回的结果数组中 Promise 的顺序与传入的顺序一致。

  4. 错误处理:
    如果传入的 Promise 数组中有一个被拒绝,Promise.all() 返回的 Promise 也会被拒绝,并且拒绝的原因会是第一个被拒绝的 Promise 的原因。这使得错误处理变得简单,因为你只需要在一个地方处理错误,而不是在每个单独的 Promise 中。

  5. 非 Promise 值:
    如果传入的数组中包含非 Promise 值,Promise.all() 会将这些值直接放入结果数组中,而不是等待它们。

7. Promise.race 方法

语法:Promise.race (iterable) ,接收一个promise对象作为元素的数组,返回一个promise
race翻译过来有比赛的意思, 顾名思义,第一个完成的 promise 的结果状态就是最终的结果状态

示例代码:

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 更快完成
}).catch(error => {
  console.error('An error occurred:', error);
});

总结:

  1. 比较多个 Promise:
    Promise.race() 用于比较多个 Promise 对象,看哪一个会最先完成(兑现或拒绝)。它类似于一场“比赛”,看哪个 Promise 会“赢”。

  2. 返回最快的结果:
    一旦传入的 Promise 对象中有一个改变了状态(无论是兑现还是拒绝),Promise.race() 返回的新的 Promise 对象会立即以同样的状态和值(或拒绝原因)完成。这意味着你只会得到最快完成的那个 Promise 的结果或错误。

  3. 应用场景:
    Promise.race() 通常用于需要等待多个异步操作中的任何一个完成的情况。例如,你可能想要并行发起多个网络请求,但只需要第一个返回的结果。或者,你可能想要设置一个超时机制,如果某个操作在一定时间内没有完成,就执行另一个操作。

  4. 错误处理:
    如果传入的 Promise 对象中有一个被拒绝,并且你没有为 Promise.race() 返回的 Promise 提供错误处理函数(.catch()),那么该错误会被抛出。因此,通常建议在使用 Promise.race() 时提供错误处理逻辑。

  5. 空的可迭代对象:
    如果传入 Promise.race() 的可迭代对象为空,那么返回的 Promise 对象将永远不会改变状态,它会一直处于挂起状态。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值