一,模拟异步请求
使用回调函数返回请求到的异步数据
function requestData(url, successCallback, failtureCallback) {
// 异步操作:网络请求
setTimeout(() => {
if (url === "sun") {
// 请求成功
const res = ["sun", "james", "lebron"];
successCallback(res);
} else {
// 请求失败
const error = "路径错误";
failtureCallback(error);
}
}, 3000);
}
requestData(
"sn",
function (res) {
console.log(res);
},
function (error) {
console.log(error);
}
);回调函数的痛点:
当需要多个异步操作嵌套使用的话会导致代码的可读性差,代码不规整,造成回调地狱。
异步请求的定义与使用需要大量的沟通成本。
使用Promise重构什么是Promise? promise是一个类。在网络请求函数中可以给调用者返回一个承诺对象,通过这个承诺可以拿到成功或者失败的返回响应。 在这个承诺对象中需要传入一个executor回调函数,这个回调函数会立即执行,并且需要给这个函数传入另外两个回调函数:resolver和reject。当调用resolve函数时,会执行promise对象的then方法,当调用reject函数时,会执行promise对象中的catch方法。
function requestData(url) {
// 异步操作:网络请求
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url === "sun") {
// 请求成功
const res = ["sun", "james", "lebron"];
resolve(res);
} else {
// 请求失败
const error = "路径错误";
reject(error);
}
}, 3000);
});
}
requestData("sun")
.then((res) => {
console.log(res); //[ "sun", "james", "lebron" ]
})
.catch((error) => {
console.log(error); //路径错误
});Promise的代码结构Promise使用过程,可以将它划分成三个状态:
1,待定(pending): 初始状态,既没有被兑现,即也没有被拒绝;当执行executor中的代码时,处于该状态;
2,已兑现(fulfilled): 意味着操作成功完成,即执行了resolve时,处于该状态;
3,已拒绝(rejected): 意味着操作失败,即执行了reject时,处于该状态;
new Promise((resolve, reject) => {
resolve("成功"),
reject("拒绝");
}).then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);resolve方法参数
1,如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数。
2,如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态。
3,如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据then方法的结果来决定Promise的状态。
const newPromise = new Promise((resolve, reject) => {
resolve("传入的是一个promise对象");
});
const obj = {
then: function (resolve, reject) {
resolve("传入的是一个具有then方法的对象");
},
};
new Promise((resolve, reject) => {
// resolve("成功"),
// resolve(newPromise);
resolve(obj);
reject("拒绝");
}).then(
(res) => {
// console.log(res); //"成功"
// console.log(res); //"传入的是一个promise对象"
console.log(res); //"传入的是一个具有then方法的对象"
},
(err) => {
console.log(err);
}
);then方法then方法接受两个参数:
fulfilled的回调函数:当状态变成fulfilled时会回调的函数;
reject的回调函数:当状态变成reject时会回调的函数;
then方法的多次调用:
const promise = new Promise((resolve, reject) => {
resolve("aaa");
});
promise.then((res) => {
console.log("res1", res);
});
promise.then((res) => {
console.log("res2", res);
});
// res1 aaa
// res2 aaathen方法的返回值: then方法的返回值也是一个Promise对象,所以可以对promise进行链式调用。then方法返回的Promise也有三种状态:
当then方法中的回调函数本身在执行的时候,那么它处于pending状态;
当then方法中的回调函数返回一个结果时,那么它处于fulfilled状态,并且会将结果作为resolve的参数;
- 情况一:返回一个普通的值;
- 情况二:返回一个Promise;
- 情况三:返回一个thenable值;
当then方法抛出一个异常时,那么它处于reject状态;
const promise = new Promise((resolve, reject) => {
resolve("aaa");
});
promise
.then((res) => {
return "sun";
// return "sun" 相当于return一个新的promise,并把执行resolve("sun")
// return new Promise((resolve, reject) => {
// resolve("sun");
// });
})
.then((res) => {
console.log(res);
});catch方法一个Promise的catch方法是可以被多次调用的:每次调用我们都可以传入对应的reject回调;当Promise的状态变成reject或者executor中发生异常的时候,这些回调函数都会被执行; 在执行promise的then方法时传入的第二个回调函数会在executor中reject函数执行的时候触发。但是当链式调用的时候then方法需要传入两个回调函数会造成阅读性较差。所以就可以通过catch方法进行捕获。
const promise = new Promise((resolve, reject) => {
resolve("sun");
// reject("aaa");
// throw new Error("有异常");
});
promise
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log("err1", err);
});需要注意的是,catch可以看作是一个es6语法糖,它是先捕获promise中的异常再捕获then中返回的new Promise对象的异常。
catch方法的返回值catch方法的返回值也是一个新的promise对象,然后把返回的内容resolve出去,注意不是reject出去。
finally方法finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象无论变成fulfilled还是reject状态,最终都会被执行的代码。finally方法是不接收参数的,因为无论前面是fulfilled状态,还是reject状态,它都会执行。
const promise = new Promise((resolve, reject) => {
resolve("sun");
// reject("aaa");
// throw new Error("有异常");
});
promise
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log("err1", err);
})
.finally(() => {
console.log("finally方法执行");
});Promise类方法:resolve前面的then、catch、finally方法都属于Promise的实例方法,都是存放在Promise的prototype上的。 以下是Promise的一些类方法。 场景:有时候我们已经有一个现成的内容了,希望将其转成Promise来使用,这个时候我们可以使用 Promise.resolve 方法来完成。Promise.resolve的用法相当于new Promise,并且执行resolve操作。
const obj = {
name: "sun",
};
function foo(obj) {
return new Promise((resolve, reject) => {
resolve(obj);
});
}
foo(obj).then((res) => {
console.log(res); //{ name: "sun" }
});
// 使用Promise.resolve
Promise.resolve(obj).then((res) => {
console.log(res); //{ name: "sun" }
});Promise类方法:all它的作用是将多个Promise包裹在一起形成一个新的Promise; 新的Promise状态由包裹的所有Promise共同决定:
当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值组成一个数组;
当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数;
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p1");
}, 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p2");
}, 2000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p3");
}, 3000);
});
Promise.all([p1, p2, p3, "aaa"]).then((res) => {
console.log(res); //[ "p1","p2", "p3", "aaa" ]
});Promise类方法:allSettledall方法有一个缺陷:当有其中一个Promise变成reject状态时,新Promise就会立即变成对应的reject状态。那么对于resolved的,以及依然处于pending状态的Promise,是获取不到对应的结果的;
在ES11(ES2020)中,添加了新的API Promise.allSettled。
该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是reject时,才会有最终的状态;
并且这个Promise的结果一定是fulfilled的
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p1");
}, 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p2");
}, 2000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("p3");
}, 3000);
});
Promise.all([p1, p2, p3, "aaa"])
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err); //p3
});
Promise.allSettled([p1, p2, p3, "aaa"]).then((res) => {
console.log(res);
});
// [
// { status: "fulfilled", value: "p1" },
// { status: "fulfilled", value: "p2" },
// { status: "rejected", reason: "p3" },
// { status: "fulfilled", value: "aaa" }
// ]Promise类方法:race如果有一个Promise有了结果,就希望决定最终新Promise的状态,那么可以使用race方法:race是竞技、竞赛的意思,表示多个Promise相互竞争,谁先有结果,那么就使用谁的结果;
Promise.race([p1, p2, p3]).then((res) => {
console.log(res); //p1
});Promise类方法:anyany方法是ES12中新增的方法,和race方法是类似的,any方法会等到一个fulfilled状态,才会决定新Promise的状态;如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态,会报一个AggregateError的错误。
Promise.any([p1, p2, p3]).then((res) => {
console.log(res); //p1
});