前言🎃
Promises(期约)
我们一起定个约定好不好,“等你瘦了,我就做你女朋友”,如果你失败了,那就。。。
之后我就在努力减肥。。。
减肥成功了😊: 我们一起去看美丽的风景 💕
减肥失败了😔:没事的,我看到了你的努力,你做我男朋友好不好
主要内容🎃
- Promise与异步编程
前置知识
为什么出现异步编程?
js是建立在单线程事件循环的概念之上的。单线程意味着同一时刻只能执行一段代码。这是它的特点。所以它适用于操作dom树。
补充:事件循环(event loop )是 JS 引擎的一个内部处理线程,能监视代码的执行并管理作业队列。
但是也有一些其他情况,如果遇到代码A比较耗时的时候,我们需要一直等待,但是这样体验并不是我们想要的。
因为它不影响我下一段代码的执行.所以我们希望在等待的过程中,执行下一段代码B。这样我们就需要定一个期约。也就是约定,因为怕它过太长时间忘记。以后我要通过这个约定来办的事情。
let promise = new Promise(function(resolve, reject) {
console.log("Promise");
resolve();
});
// promise 就是一个约定(但是不知道结果是什么呢)
// 即使过了很多年,我也可以靠这个约定调用then方法,来办事情,
// 如果成功就这样办,如果失败就那样办。如果中间不在了(遇到错误),直接抛出错误
promise.then(function() {
console.log("Resolved.");
},function(){
console.log();
}).catch(error){
conole.log('error',error)
};
浏览器中自己也设置一些耗时的需要异步执行的
比如:定时器线程 http请求 页面渲染
补充知识点:
-
一个浏览器可以有多个进程
-
每一个tab页面都是一个进程,一个进程可以多个线程,包含js线程,渲染线程等
回顾以往的异步编程背景
第一种:事件模型
当我们写一个点击事件的时候,其实就是一个事件被触发,该事件的处理函数被加到一个作业队列的尾部。等待执行。
let button = document.getElementById("myBtn");
button.onclick = function(event) {
console.log("Clicked");
};
第二种: 回调模式
Node.js 使用了异步回调方式,错误优先的原则,同样是一个新的作业添加到作业队列的尾部。下面代码展示了回调模式。
readFile("example.txt", function(err, contents) {
// 新的作业
if (err) {
throw err;
}
console.log(contents);
});
console.log("Hi!");
第三种:解决回调地狱
下面介绍了Promise来解决这个问题,🤔其他方案还有吗?(可以评论区留言)
Promise与异步编程🎃
第一步:先简单实现一个Promise
let promise = new Promise(function(resolve, reject) {
// 1
console.log("Promise");
resolve();
});
promise.then(function() {
// 3 A
console.log("Resolved.");
});
// 2
console.log("Hi!");
// Promise
// Hi
// Resolved
思路解析:
-
promise执行器里先执行
-
then()方法把要执行的函数A加到作业队列的尾部
-
执行打印语句log('Hi')
-
执行队列里的函数A
promise的生命周期
- 挂起状态:pending (这时不知道结果是什么)
- 知道结果后有两种: 已完成(fulfilled) 已拒绝(rejected)
promise的方法(不一一展开,可以自己查询使用方法)
-
Promise.then()
-
Promise.catch()
-
Promise.resolve()
-
Promise.reject()
以上的方法都可以单独执行,例如下面的这个例子
let promise = Promise.reject(42);
promise.catch(function(value) {
console.log(value); // 42
});
看一下Promise.all() 与 Promise.race()的测试,我们一起分析它们的不同之处
let promise1 = new Promise(function(reslove,reject){
setTimeout(function () {
console.log('传过去3');
reslove(3)
},3000)
});
let promise2 = new Promise(function(reslove,reject){
setTimeout(function () {
console.log('传过去1');
reslove(1)
},2000)
});
// all测试
Promise.all([promise1,promise2]).then(result=>{
console.log('all的结果是',result);
}).catch(error=>{
console.log(error);
});
// race 测试
Promise.race([promise1,promise2]).then(result=>{
console.log('race的结果是',result);
}).catch(error=>{
console.log(error);
});
上面结果显示,race方法返回的是1这一个值,all返回的是[3,1]两个值,但是两个都是先执行的promise2(因为耗时短),因此我们能想到:race返回最快执行的某一个结果,而all()方法会按照之前数组的顺序。
扩展思考🤔:对于返回错误,或抛出错误,它们是如何应对的呢?(欢迎评论留言)
promise在不同环境的错误处理
- 执行器错误❌
let promise = new Promise(function(resolve, reject) {
throw new Error("我要报错!");
});
promise.catch(function(error) {
console.log(error.message); // "我要报错!"
})
这种情况,在执行器处理中会捕捉错误,并抛出错误
- promise在Node.js 和浏览器中的拒绝处理
当Promise 被 reject 且没有 reject 处理器的时候,会触发 unhandledrejection 事件;这可能发生在 window 下,但也可能发生在 Worker 中。 这对于调试回退错误处理非常有用。
let promise1;
process.on("unhandledRejection", function(reason, promise) {
console.log(reason.message); // "报错了!"
console.log(promise1 === promise); // true
});
promise1 = Promise.reject(new Error("报错了!"));
//报错了!
//true
这块,可以作为一个话题,欢迎在评论区讨论相关问题。
promise异步编程开发实践
利剑1🔪:利用好链式调用
前端调接口是否有这样的场景?
用接口1的结果作为参数请求接口2,用接口2的结果作为参数请求接口3
new Promise(function(reslove,reject){
// 操作:请求接口1
// 返回接口1结果
reslove('接口1结果')
}).then(res=>{
//拿到res(接口1的结果)
// 操作:请求接口2
// 返回接口2结果
reslove('接口2结果')
}).then(res1=>{
//拿到res1(接口2的结果)
// 操作:请求接口3
// 返回接口3结果
reslove('接口2结果')
}).catch(error=>{
console.log(error);
})
利剑2🔪:利用好Promise.all()和Promise.race()
前端调接口是否有这样的场景?
**用接口1的结果和接口2的结果去请求接口3
let promise1 = new Promise(function(reslove,reject){
// 接口1请求
reslove('接口1结果')
});
let promise2 = new Promise(function(reslove,reject){
// 接口2请求
reslove('接口2结果')
});
// 请求接口3
Promise.all([promise1,promise2]).then(result=>{
//接口1,2的结果是:result
// 请求接口3
}).catch(error=>{
console.log(error);
});
前端调接口是否有这样的场景?
**用接口1的结果或接口2的结果去请求接口3
let promise1 = new Promise(function(reslove,reject){
// 接口1请求
reslove('接口1结果')
});
let promise2 = new Promise(function(reslove,reject){
// 接口2请求
reslove('接口2结果')
});
// 请求接口3
Promise.race([promise1,promise2]).then(result=>{
//接口1或2的结果是:result(获取请求最快的那个)
// 请求接口3
}).catch(error=>{
console.log(error);
});