小小异步,看我Promise直接把你优雅拿下!
前言
今天我们一起学习JavaScript的ES6版本中引入的处理异步操作的对象---Promise
。在学习Promise之前呢,我先带大家了解一下什么是异步。
同步和异步
在编程中,同步和异步是两种不同的模式,同步操作是顺序执行的,一个任务必须等待前一个任务完成后才能开始。例如,在同步调用函数时,调用方会被阻塞,直到被调用的函数返回结果;而异步操作则是非阻塞的,任务可以同时进行,不必等待前一个任务完成。比如异步网络请求,发出请求后程序可以继续执行其他操作,无需等待响应。
所以同步比较适合处理少量,简单的任务,异步能够充分利用系统资源,比较适合处理一些复杂或者耗时的任务。
早期异步的处理
为了让大家更直观地了解到Promise的“优雅”之处,我们先来了解一下没有Promise之前,是怎么处理异步操作的。
- 早期我们主要通过回调函数来处理异步操作:
var data = null
function a(cb) {
setTimeout(function () {
data = 'hello world'
cb()
}, 1000);
}
function b() {
console.log(data);
}
a(b)//hello world
回调函数指的是将函数(本身)作为参数传递给另一个函数。当特定的事件发生或操作完成时,主函数会调用这个传递进来的回调函数来执行相应的操作。在这里,b
就是回调函数,它被作为参数传递给了函数a
,a
接收并调用了函数b
,使得打印结果为hello world
而并不是null
。这样就实现了异步操作。
单从这段代码来看,回调函数处理异步操作是不是还挺方便的呢?但是一旦代码量多了起来,嵌套了多层回调函数,实现和修改起来就会极其的麻烦,牵一发而动全身,这种情况我们通常称为“回调地狱”。
Promise
为了更优雅地执行异步操作,在Js的ES6版本中引入了Promise
:
Promise
是一个用于处理异步操作的对象,它代表一个还没完成但最终会完成(或失败)并返回其结果值的异步操作。
它可以是以下三种状态之一:
pending
(进行中):异步操作正在进行resolve
(已完成):异步操作已完成,并有一个结果值reject
(已失败):异步操作执行失败,并有一个错误
创建Promise对象
const pro = new Promise((resolve,reject) =>{
//模拟异步操作
setTimeOut(() =>{
if(/* 异步操作成功 */){
resolve("操作成功");
}else{
reject("数据获取失败");
}
},1000)
})
Promise
对象通过构造函数创建,并接收一个执行器函数作为参数,该执行器函数会立即执行,并有两个参数:resolve
,reject
,分别用来改变promise
对象的状态。
.then() / .catch() / .finally() 方法
这些方法是promise对象自带的方法,其中, .then()
方法用来处理成功的状态:即如果promise对象的状态被切换为resolve
,就会执行.then()
中的代码。.catch()
用于捕获 Promise 链中的错误,通常用在.then()
的后面,当状态被切换成reject
或者.then()
中的执行出现错误,都会执行.catch()
中的代码。我们还可以使用.finally()
方法来处理无论成功还是失败都会执行的代码。
pro.then(value =>{
console.log('状态:',value) //状态:操作成功
})
.catch(error =>{
console.log('捕获错误:',error) //捕获错误:数据获取失败
})
.finally(() =>{
console.log(无论成功或者失败,都会执行'')
})
- 链式调用:Promise支持链式调用,这意味着我们可以在一个promise对象后面接多个
.then()
,.catch()
:
pro
.then(result => {
console.log('第一个then成功:', result);
return '我是第二个then';
})
.then(result2 => {
console.log('第二个then成功:', result2);
})
.catch(error => {
console.log('某个then或之前的catch失败:', error);
});
.all() / .race() 方法
.all()
方法可以用来处理多个promise,调用时接收一个数组,返回一个promise对象:数组里的每一项都得是promise对象,只有当这些promise都成功时,才能返回一个成功的promise;只要有一个promise不成功,就会返回一个失败的promise。
Promise.all([promise1, promise2])
.then(results => {
console.log('所有的Promise都成功了:', results);
})
.catch(error => {
console.error('至少有一个Promise失败了:', error);
* .race()
方法同样是接收一个promise数组,但是他会立即返回第一个完成的promise的结果,无论他是成功还是失败。
const p1 = new Promise((resolve,reject) => {
setTimeout(() =>{
console.log("p1");
},1000)
})
const p2 = new Promise((resolve,reject) =>{
setTimeout(() => {
console.log("p2")
},2000)
})
Promise.race([p1,p2])
.then( result => {
console.log("谁先运行成功:", result)
})
.catch( error => {
console.error("谁先运行失败:", error)
})
在这个代码示例中:显然是p1
先执行成功,所以打印的结果是谁先运行成功:p1
。因为在这个代码示例中p1
,p2
都一定会成功运行,所以不会执行.catch()
,但是如果p1
,p2
中有任何一个执行错误,都会打印先执行失败的promise对象的错误原因。
总结
Promise 提供了一种强大的方式来处理异步操作,使得代码更加清晰和易于管理。
-
当promise对象的状态从
pending
切换成resolve
时,就会执行.then()
中的代码。当状态切换为reject
时,就会被.catch()
捕捉到错误,就会执行.catch()
中的代码。且.then()
和.catch()
支持链式调用。 -
.all()
和.race()
方法是Promise身上的静态方法。.all()
会接收一个promise数组作为参数,当数组中所有的promise对象都执行成功,则返回一个成功的Promise,否则就返回一个失败的Promise。 -
.race()
同样接收一个promise数组,它会返回第一个执行完毕的promise的执行结果,无论是成功或失败。
转载自:https://juejin.cn/post/7389446501133762598