JS之Promise
为什么需要 promise
首先,存在一次异步任务的需求。然后又有了多次异步任务的需求,而多次异步的书写存在函数瀑布问题,不利于阅读和维护:
setTimeout(function () {
console.log("First");
setTimeout(function () {
console.log("Second");
setTimeout(function () {
console.log("Third");
}, 3000);
}, 4000);
}, 1000);
所以,出现了 promise 对象,将多次异步代码写成顺序格式而非嵌套格式:
function print(delay, message) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(message);
resolve();
}, delay);
});
}
print(1000, "First")
.then(function () {
return print(4000, "Second");
})
.then(function () {
print(3000, "Third");
});
因此,异步是异步,promise 是 promise,异步任务的实现靠的是 javascript 的事件循环机制,而不是 promise,promise 仅是改变了需要按顺序执行的多个异步任务的书写格式。
promise 的本质
Promise 是一个构造函数,它接收一个函数作为形参,实例化一个 p 对象。相比于普通对象,p 对象有两个特殊属性:状态和结果。
状态
通过在形参函数中调用 resolve()和 reject()改变状态,并且只能改一次.状态有三种,分别是 pending/fullfilled/reject.没执行 resolve() or reject()之前的状态是 pending。
结果
通过 resolve/reject 函数传递参数,改变当前 promise 对象结果
const p = new Promise((resolve, reject) => {
resolve("homo");
});
console.log(p); // state:fullfilled, result:'homo'
构造函数和 then 方法
promise 是靠多个 then 完成多个异步任务的按顺序执行的。怎么实现的?then 可以注册 resolve 和 reject。若要嵌套,要写成下面这种形式,return 一个新的 promise,value 在异步代码中使用。
new Promise((resolve) => {
// setTimeout(()=>{
// resolve('1')
// },500)
})
.then((value) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(value + " 2");
});
});
})
.then((value) => {
// console.log(value);
});
把 promise 对象当作一个容器,里面装了一个异步事件,promise 对象保证了当前异步事件执行完毕才会执行下一个事件。
-
构造实例 构造函数接受一个函数作为参数 调用构造函数得到实例 p 的同时,作为参数的函数会立即执行 参数函数接受两个回调函数参数 resolve 和 reject 在参数函数被执行的过程中,如果在其内部调用 resolve,会将 p 的状态变成 fulfilled,或者调用 reject,会将 p 的状态变成 rejected
-
调用.then 调用.then 可以为实例 p 注册两种状态回调函数 当实例 p 的状态为 fulfilled,会触发第一个函数执行 当实例 p 的状态为 rejected,则触发第二个函数执行
如果代码执行出现错误,而没有 catch 或者 then 接受错误的话,控制台会报错。
下面的代码可以充分体现了,promise 对象解决了异步函数的多重回调问题。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
function getData(url, data={}){
return new Promise((resolve, reject)=>{
$.ajax({
type:'GET',
url:url,
data:data,
success:function(res){
const {result} = res
console.log(res);
resolve(result)
}
})
})
}
getData('data1.json').then((value)=>{
getData('data2.json', value)
} )
</script>
</body>
</html>
Promise.all()
作用:一次接受多个异步事件,并保证他们的都得到结果了,才会执行 then 输入参数:数组、map 等 输出:一个新的 promise 对象,根据数组中所有 promise 的执行结果而进入不同的函数。若数组中所有的 promise 都是 fullfilled,则会执行 then。
Promise.any()
作用:一次接受多个异步事件,其中有一个成功就行 输入参数:数组、map 等
Promise.resolve(p)/reject(p)
返回一个状态为 fullfilled/rejected,结果为 p 的 promise 对象。