各位小伙伴,又见面啦 ! 今天给大家讲讲promise吧
众所周知,回调函数噩梦(恐怖回调),也被称为恶魔金字塔,指如ajax依赖调用时,回调函数会层层嵌套,而这种层层嵌套的写法,往往会让人难以理解,所以称之为噩梦。
例如:服务器中有3个txt文件,我们需要在html上,通过js中的异步的ajax,分别获取这3个文件的内容,假设这3个文件分别存储的数据为1、2、3,那么我希望在js中,能够求出1+2+3,把6输出。
var str = "";
$.ajax({
type: "get",
url: "../data/1.txt",
success: function (msg1) {
str += msg1;
setTimeout(function () {
$.ajax({
type: "get",
url: "../data/2.txt",
success: function (msg2) {
str += msg2;
$.ajax({
type: "get",
url: "../data/3.txt",
success: function (msg3) {
str += msg3;
console.log(str);
}
})
}
})
}, 10)
}
})
看到以上这个代码是不是头都大了, Promise就是解决这种回调函数噩梦的方案之一(Promise 是异步编程的一种解决方案),所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
Promise对象代表一个异步操作,有三种状态:
pending (进行中)
Resolved(已完成,又称Fulfilled)
Rejected(已失败)
注:可以把Promise看成是状态机,当该Promise对象创建出来之后,其状态就是进行中,然后通过程序来控制到底是执行已完成,还是执行已失败。因为Promise处理的是异步任务,所以我们还得对Promise做监听,当Promise的状态发生变化时,我们要执行相应的函数。
一、 Promise的特点
1. 对象的状态不受外界影响 => 想要改变状态 需要借助 resolve,rejected 方法
2. Promise对象一经改变,不能再次改变
二、Promise的优缺点
优点: 有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
缺点:
1. 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2. 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。(直接报错)
3. 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
三、实例方法
then(callback1,callback2)
callback1 当promise实例的状态 由进行中(pending)改为已成功(fullilled)时执行回调函数
callback2 当promise实例的状态 由进行中(pending)改为已失败(rejected)时执行回调函数,也可以接收代码执行过程中的语法错误/手动抛错throw
new Promise(function (resolve, reject) {
// 模拟异步操作
setTimeout(function () {
var num = parseInt(Math.random() * 10);
if (num % 2 == 0) {
resolve("我是成功的num" + num);
} else {
reject("我是失败的num" + num);
}
})
}).then(function (result) {
// 成功时执行
console.log(result);
}, function (err) {
// 失败时执行
console.log(err);
})
catch()
该方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。
Tips: Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
new Promise(function (resolve, reject) {
// 模拟异步操作
setTimeout(function () {
var num = parseInt(Math.random() * 10);
if (num % 2 == 0) {
resolve("我是成功的num" + num);
} else {
reject("我是失败的num" + num);
}
})
}).then(function (result) {
// 成功时执行
console.log(result);
}).catch(err => {
// 失败时执行
console.log(err);
})
finally() 不管成功还是失败都会执行
new Promise(function (resolve, reject) {
// 模拟异步操作
setTimeout(function () {
var num = parseInt(Math.random() * 10);
if (num % 2 == 0) {
resolve("我是成功的num" + num);
} else {
reject("我是失败的num" + num);
}
})
}).then(function (result) {
// 成功时执行
console.log(result);
}).catch(err => {
// 失败时执行
console.log(err);
}).finally(()=>{
console.log("到达终点")
})
四、构造函数的方法
Promise.all() 用于将多个 Promise 实例,包装成一个新的 Promise 实例
Promise.all([p1, p2, p3]) => p
p的状态由p1、p2、p3决定,分成两种情况:
a. 只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
b. 只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
// 只要p1,p2,p3中有一个状态为rejected,p的状态则为rejected,否则为fulfilled
var p = Promise.all([p1, p2, p3]);
p.then(function (list) {
console.log(list);
}).catch(err => {
console.log(err);
})
Promise.allSettled() 用于将多个 Promise 实例,包装成一个新的 Promise 实例
只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束
Tips: 一旦结束,状态总是fulfilled,不会变成rejected
Promise.race() 用于将多个 Promise 实例,包装成一个新的 Promise 实例
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数
Promise.resolve() 快速生成一个fulilled状态 Promise实例,并将传入的参数作为实例的返回值
// 参数是一个实例
console.log(Promise.resolve(1));
// 参数是一个 thenable对象
var p = Promise.resolve({
then: function (resolve, reject) {
var num = Math.round(Math.random() * 10);
// console.log(num);
if (num % 2 == 1) {
resolve("我是失败的" + num);
} else {
reject("我是失败的" + num);
}
}
})
p.then(result => {
console.log(result);
).catch(err => {
console.log(err);
})
Promise.reject() 快速生成一个rejected状态 Promise实例,并将传入的参数作为实例的返回值