ES6-Promise上
一。Promise作用:解决回调地狱问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Promise 是什么</title>
<style>
* {
padding: 0;
margin: 0;
}
#box {
width: 300px;
height: 300px;
background-color: red;
transition: all 0.5s;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
// 1.认识 Promise
// Promise 是异步操作的一种解决方案
// 回调函数
// document.addEventListener(
// 'click',
// () => {
// console.log('这里是异步的');
// },
// false
// );
// console.log('这里是同步的');
// 2.什么时候使用 Promise
// Promise 一般用来解决层层嵌套的回调函数(回调地狱 callback hell)的问题
// 运动
const move = (el, { x = 0, y = 0 } = {}, end = () => {}) => {
el.style.transform = `translate3d(${x}px, ${y}px, 0)`;
el.addEventListener(
'transitionend',
() => {
// console.log('end');
end();
},
false
);
};
const boxEl = document.getElementById('box');
document.addEventListener(
'click',
() => {
move(boxEl, { x: 150 }, () => {
move(boxEl, { x: 150, y: 150 }, () => {
move(boxEl, { y: 150 }, () => {
// console.log('object');
move(boxEl, { x: 0, y: 0 });
});
});
});
},
false
);
</script>
</body>
</html>


二。实例Promise,实例的then方法,resolve和reject函数及其参数,Promise三种状态

第一个参数是成功态,第二个是失败态;

pending等待状态,箭头函数函数体里面没调用resolve 和 reject 时,只要实例一个Promise就是这个状态,可以理解为初始状态

当我们执行resolve方法后,变成成功状态 pending---fulfilled

当我们执行reject方法后,变成失败状态 pending---rejected

注意:只要promise回调函数这个实参函数体里面写了resolve()或者reject(),都可以改变状态;
const p = new Promise(function (resolve, reject) { function fn() { resolve()//这个位置(写在其他函数体里)写了resolve()也能将p的状态转换成成功态 }; fn(); }); console.log(p);//Promise {<fulfilled>: undefined}
如果resolve 和 reject 都在箭头函数里调用:没有成功<--->失败态之间的转变,只有初始-->成功或者初始-->失败;

Promise实例都有then方法(其实是构造函数.prototype的方法--实例可以访问原型的方法属性),p调用then方法p本身不会变

可以理解then方法内部判断p的状态,然后再内部决定调用哪个回调函数;
resolve 和 reject 方法的参数:reject 方法同理


请问三种状态指的是实例的还是构造函数的,应该指的是实例的吧?-----对!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Promise 的基本用法</title>
</head>
<body>
<script>
// 1.实例化构造函数生成实例对象
// console.log(Promise);
// Promise 解决的不是回调函数,而是回调地狱
// const p = new Promise(() => {});
// 2.Promise 的状态
// const p = new Promise((resolve, reject) => {
// // Promise 有 3 种状态,一开始是 pending(未完成),执行 resolve,变成 fulfilled(resolved),已成功
// // 执行 reject,变成 rejected,已失败
// // Promise 的状态一旦变化,就不会再改变了
// // pending->fulfilled
// // resolve();
// // pending->rejected
// reject();
// });
// 3.then 方法
// p.then(
// () => {
// console.log('success');
// },
// () => {
// console.log('error');
// }
// );
// 4.resolve 和 reject 函数的参数
const p = new Promise((resolve, reject) => {
// Promise 有 3 种状态,一开始是 pending(未完成),执行 resolve,变成 fulfilled(resolved),已成功
// 执行 reject,变成 rejected,已失败
// Promise 的状态一旦变化,就不会再改变了
// pending->fulfilled
// resolve('succ');
// resolve({ username: 'alex' });
// pending->rejected
// reject('reason');
reject(new Error('reason'));
});
p.then(
data => {
console.log('success', data);
},
err => {
console.log('error', err);
}
);
console.log(p);
</script>
</body>
</html>
三。实例的then方法


执行第一个回调函数

then方法内部调用哪个回调函数(then方法的两个实参)取决于调用then方法的promise实例他的状态

then里面回调函数的返回值就是Promise实例调用then方法的返回值;

then里面的异步:(挂起)



then里面的回调是异步,所以先执行打印p2;
未展开之前的状态才是执行console.log(p2)语句输出p2时的结果,即pending状态(虽然p2还没完成彻底赋值,里面的回调是异步,但是打印p2已经是promise实例了,只不过是pending状态)
展开后查看的是p2最终的结果,也就是说p2最终是会变成fulfilled状态,但是由于代码是异步执行的,所以在执行console.log(p2)输出时p2的状态为pending状态

假如程序执行时调用then的实例是pending,那这段调用then的代码会挂起,继续执行接下来要执行的同步异步等代码(挂起目的就是等待实例状态变化再来调用then,就是回头又执行),等这个实例状态变化了就会马上执行then(挂起状态结束),不论then里面的回调是否执行,这段代码不会再回头执行了;
注意,如果程序执行时,实例打点调用then,这个实例的状态确定,就不存在挂起这回事了;都是直接执行then或者跳过(比如成功态调用catch),不存在回头了
下图,程序执行p1.then时,p1此时虽然赋值还没结束,但是已经是promise实例了,只不过是pending状态


注意:return后面不是promise实例时,直接写个return 数据,不写return也是return undefined ,就相当于return new Promise(function(resolve,reject){
resolve(数据)
});------------------这就是默认用promise包装一下
且默认都是调用resolve(),所以then方法返回的是成功状态的promise实例;
return后面是promise实例时,就不会包装了;

// 1.什么时候执行 // pending->fulfilled 时,执行 then 的第一个回调函数 // pending->rejected 时,执行 then 的第二个回调函数 // 2.执行后的返回值 // then 方法执行后返回一个新的 Promise 对象 // const p = new Promise((resolve, reject) => { // resolve(); // // reject(); // }); // const p2 = p // .then( // () => {}, // () => {} // ) // .then() // .then(); // console.log(p, p2, p === p2); // 3.then 方法返回的 Promise 对象的状态改变 // const p = new Promise((resolve, reject) => { // // resolve(); // reject(); // }); // p.then( // () => { // // console.log('success'); // }, // () => { // console.log('err'); // // 在 then 的回调函数中,return 后面的东西,会用 Promise 包装一下 // // return undefined; // // 等价于 // // return new Promise(resolve => { // // resolve(undefined); // // }); // return 123; // // return new Promise(resolve => { // // resolve(123); // // }); // // 默认返回的永远都是成功状态的 Promise 对象 // // return new Promise((resolve, reject) => { // // reject('reason'); // // }); // } // ) // .then( // data => { // console.log('success2', data); // // return undefined; // return new Promise(resolve => { // resolve(undefined); // }); // }, // err => { // console.log('err2', err); // } // ) // .then( // data => { // console.log('success3', data); // }, // err => { // console.log('err3', err); // } // );
注意点:调用then方法的返回值只跟then方法实参(两个回调函数)return后面的东西有关,当然我们要看看这两个回调哪个执行,不执行有return也没用;
调用then方法的返回值,我们主要关注两个:返回值promise实例的状态以及其以promise包装时resolve 或者reject 的参数;状态决定其调用then方法时then的哪个回调执行,参数的话,then的回调形参接收promise包装时resolve 或者reject 的参数;
如果连续打点调用then方法,就按照如下思路分析,不容易乱:

注意点:Promise构造器里面的回调函数里面的形参的顺序 :第一个一定是成功态,第二个一定是失败态,虽然不一定要写全形参
then里面的回调函数也是要注意顺序:第一个参数(回调函数)一定是Promise实例为成功态时被then内部调用,第二个参数(回调函数)一定是Promise实例为失败态时被then内部调用,虽然不一定要写全这两个回调函数;
四。解决回调地狱问题

重点:每一次调用movePromise会返回新的成功态p,且盒子本次达到目标位置

以下是个人更深入的理解:(挂起)

如果then中不写return,那么就相当于调用moveP后再return undefined,因为调用moveP会有过渡运动开始运动,与此同时return undefined执行,第一个实例p.then()的返回值就是默认的成功态新p马上确定了,这个p马上接着调用then方法,马上执行then的回调函数,调用moveP后再return undefined(注意此时前面then中的过度运动还没执行完毕),下一个then的移动逻辑会覆盖上一个then的效果,就会导致bug的出现。

相当于then(null,function(err){} )

直接跳过当不存在;

虽然会一直跳过往后找,失败态的实例连续一次或者多次打点调用时如果后面的then方法(catch也算是then)如果一直没有出现第二个参数,是会报错的
错误的意思就是说有个失败态的实例调用then方法一直都是无效
捕获错误就是让这个失败态实例成功调用一次then方法,让then里面的回调函数可以执行

错误提示:没有被捕获的错误;因为第一个实例是失败态,如果后面的then方法一直没有出现第二个参数(没有处理错误),是会报错的

但是成功态的实例调用then方法失效是不会报错的(then方法第一个参数为null),即使后面连续打点调用then都失效(then方法第一个参数为null),也不会报错,

跳过时的参数传递

catch方法直接看作是then方法的特例即可,一样会返回新的promise实例,和then一模一样;
前面我们想调用then方法返回一个失败态的实例,就得手动添加return new Promise(resolve,reject){reject()},在catch方法里可以使用throw,就相当于return new Promise(resolve,reject){reject(throw后面的数据)};
不仅在catch方法里。then方法也可以写throw,和catch里面用法一样


成功态实例调用then方法,如果then第一个参数为null,不会报错;如果连续打点调用then时,遇到的都是这样的then也一样不会报错,规则是遇到then第一个参数为null就直接跳过去调用下一个then
失败态实例调用then方法,then参数只有一个回调函数会报错;如果连续打点调用then时,如果所有的then都失效,会报错,如果有一个then执行了回调,那么该错误被捕获,也获得了返回值实例,如果后面接着调用then要看看返回值实例的状态,如果是失败态就得接着注意该步骤;
不论成功还是失败态,遇到失效都会跳过往下找只不过成功态找不到能执行回调的then不会报错,失败态会报错;
注意,报错不会影响后续代码的执行;

关于报错我的理解:
程序只要监测到调用了reject(),就会抛出异常,假如这个promise实例过程中调用了reject(),只要这个失败态实例打点调用then方法(例如catch)且成功执行了里面的回调函数(并没有跳过这个then),那么这个异常就消失,如果其调用then方法返回值又是一个失败态实例(返回值在实例过程中又调用了reject()),那么又会抛出异常,直到这个返回值失败态实例打点调用then方法(例如catch)且成功执行了里面的回调函数,那么这个异常就消失;
注意:捕获错误可以用then也可以用catch,catch只是特殊的then而已;
浙公网安备 33010602011771号