对于这篇文章,我们要明白Promise到底是什么东西,为什么JS官方要打造这个Promise,它能解决什么问题,然后又是怎么使用的呢,所以,我们带着这些问题,去学习Promise,这样才会由浅入深,更加了解Promise了。
Promise是什么
首先,Promise 是 JavaScript 中用于处理异步操作的一种机制,它提供了一种比传统的回调函数更加清晰和易于管理的方式来处理异步流程。
- 那么异步操作又是什么东西呢? 在
script
标签内的代码称为js代码,我们普遍认为js代码是从上往下去执行的,但是当我们的js代码碰到定时器或者异步请求数据时,就会触发异步操作,js内一些执行需要花时间的操作,都属于是异步操作。
这段js代码,程序的运行不会等待定时器执行完,而是直接跳过,执行了a=1
, 所以在碰到耗时性任务,就触发异步操作,跳过耗时任务,执行掉同步任务(也就是不需要耗大量时间的任务)。
对于函数调用,也是这样的执行机制,函数谁先被调用,谁先执行,一样的在内部会检查是否有耗时性任务,执行的时候,跳过耗时任务,最后才会执行,也就是说,js内先把同步代码执行完,然后执行异步代码。
地狱回调
"地狱回调"(Callback Hell),也被称为"金字塔之痛"(Pyramid of Doom),是指在JavaScript和其他支持异步编程的语言中,由于过多的嵌套回调函数而导致的代码可读性和可维护性急剧下降的现象。我们平时并不会见到这样的代码结构,可是它真的存在!循环嵌套。
一个典型的"地狱回调"代码可能看起来像这样:
javascript
someAsyncFunction(function(err, result1) {
if (err) {
console.error('Error in first function:', err);
} else {
anotherAsyncFunction(result1, function(err, result2) {
if (err) {
console.error('Error in second function:', err);
} else {
yetAnotherAsyncFunction(result2, function(err, result3) {
if (err) {
console.error('Error in third function:', err);
} else {
// Do something with result3
}
});
}
});
}
});
可以看到,随着异步操作的增多,代码的嵌套层次越来越深,形成了一个类似于金字塔的结构,这就是"地狱回调"的由来。
如何解决地狱回调呢
为了解决这个问题,JavaScript 社区引入了多种新的异步编程模式和语法糖,包括:
- Promises :Promises 提供了一种更优雅的方式来处理异步操作,通过
.then()
和.catch()
方法来注册回调,避免了层层嵌套。 - Async/Await:这是基于 Promises 的语法糖,使得异步代码可以像同步代码一样书写,极大地改善了代码的可读性。
通过使用这些新的异步处理方式,可以有效地避免"地狱回调",让代码更加整洁、易于理解和维护。
Async/Await
方法也很优雅,后续我们再细说,这里先看完promise。
下面是查看了MDN文档对Promise的简单描述:
官方描述:一个 Promise
代表一个在创建 promise 时不一定已知的值。它允许你将处理程序与异步操作的最终成功值或失败原因关联起来。这使得异步方法可以像同步方法一样返回值:异步方法不会立即返回最终值,而是返回一个 promise,以便在将来的某个时间点提供该值。
简述:异步方法返回一个promise实例对象,而不立即返回异步操作后的结果,这样就可以判断它的状态,是否执行成功,或者还处于等待状态,或者出现错误等,告知后面的then方法是否执行,这样就让一个异步方法可以像同步方法一样执行。
一个 Promise
必然处于以下几种状态之一:
- 待定(pending) :初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled) :意味着操作成功完成。
- 已拒绝(rejected) :意味着操作失败。
一个待定的 Promise 最终状态 可以是已兑现 并返回一个值,或者是已拒绝 并返回一个原因(错误)。当其中任意一种情况发生时,通过 Promise 的 then
方法串联的处理程序将被调用。如果绑定相应处理程序时 Promise 已经兑现或拒绝,这处理程序将被立即调用,因此在异步操作完成和绑定处理程序之间不存在竞态条件。
javascript
function a(){
setTimeout(()=>{
console.log('a is ok');
},1000)
}
function b(){
console.log('b执行')
}
a()
b()
对于这种代码我们非要让a函数先执行,再执行b,我们可以使用promise这样修改:
javascript
function a(){
return new Promise((resolve,reject)=>{ // 函数a返回一个promise
setTimeout(()=>{
console.log('a is ok');
// resolve('执行成功');
// reject('执行失败')
},1000)
})
}
function b(){
console.log('b执行')
}
a()
.then((res)=>{
console.log(res,'-------')
b()
})
.catch((err)=>{
console.log(err,'xxxxxx')
})
.then
是 Promise原型上的一个函数,x.then()函数会在x这个promise实例对象状态变更为resolved之后才执行内部逻辑,由此借助这个机制,可以将异步捋成同步。
-
如果我们在处理了异步操作后没有调用
resolve('执行成功')
,则后面的.then
无法执行了。 -
调用
resolve('执行成功')
,参数可带可不带,在.then()函数内可以查看这个参数。 -
调用
reject('执行失败')
,也可以传参。 -
下面也是一个异步操作用promise做成同步操作示例:
- 正常调用正常显示:
- 由于
.then
是 Promise原型上的一个函数,当第一个then函数不返回promise时:
- 结果却是
trival
函数先执行了,
解释如下:
- 当
live()
执行完毕并解析为一个值时,它触发了第一个.then()
。 - 第一个
.then()
执行work()
函数,但由于work()
函数的执行结果没有被返回(假设work()
不返回任何 Promise),.then()
默认会将其视为返回了一个 resolved 的 Promise。 - 这个默认的 resolved Promise 触发了下一个
.then()
,进而执行trivial()
函数。
通过这么一分析,由于work()
函数内部是异步操作,所以需要等待,第一个then会立马被执行掉,然后进行下一个then的执行,trival()函数被执行,所以trival先执行,异步的work后执行。
Promise的内容还有很多,如果有分析不正确的地方,欢迎jym帮忙改正。谢谢jym的观看,点赞收藏加关注,优质文章不容错过!