一。Promise作用:解决回调地狱问题

transitionend是过渡结束事件,只要过渡结束就会触发;
回调地狱:指的是层层嵌套的回调函数,代码看起来非常晕

<!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,且盒子本次达到目标位置

<!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>
    <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>
        const box = document.getElementById('box')
        const move = function (el, { x = 0, y = 0 } = {}, end = function () { }) {
            el.style.transform = `translate3d(${x}px,${y}px,0)`;
            el.addEventListener(
                'transitionend',
                function () {
                    end();
                }
            );
        };
        const movePromise = function (el, point) {//只要调用movePromise(),那么就会调用move(),过渡做完resolve执行,promise实例状态转化成成功,再打点调用then方法里面的回调才会执行
            return new Promise(function (resolve, reject) {
                move(el, point, function () {//promise里面的回调函数一定会被执行
                    resolve();
                });
            });
        };
        document.addEventListener('click', function () {
            movePromise(box, { x: 100 }).then(function () {
                return movePromise(box, { x: 100, y: 100 })
            }).then(function () {
                return movePromise(box, { x: 0, y: 100 })
            }).then(function () {
                return movePromise(box, { x: 0, y: 0 })
            })
        })
        //只要调用一次movePromise 就会返回一个新的promise实例,且这个新实例p生成的过程中会调用move(),过渡做完resolve执行,该promise实例状态转化成成功,此时调用movePromise 完毕,再打点调用then方法,then里面的回调执行
       
        // document.addEventListener('click', function () {
        //     move(box, { x: 100 }, function () {
        //         move(box, { x: 100, y: 100 }, function () {
        //             move(box, { x: 0, y: 100 }, function () {
        //                 move(box, { x: 0, y: 0 });
        //             });
        //         });
        //     });
        // })
    </script>
</body>
</html>

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

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

 五。实例的catch方法

相当于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而已;

ES6-Promise上的更多相关文章

  1. 通过 ES6 Promise 和 jQuery Deferred 的异同学习 Promise

    Deferred 和 Promise ES6 和 jQuery 都有 Deffered 和 Promise,但是略有不同.不过它们的作用可以简单的用两句话来描述 Deffered 触发 resolve ...

  2. Es6 Promise 用法详解

     Promise是什么??    打印出来看看  console.dir(Promise) 这么一看就明白了,Promise是一个构造函数,自己身上有all.reject.resolve这几个眼熟的方 ...

  3. ES6 Promise 全面总结

    转载:点击查看原文 ES6 Promise对象 ES6中,新增了Promise对象,它主要用于处理异步回调代码,让代码不至于陷入回调嵌套的死路中. @-v-@ 1. Promise本质 Promise ...

  4. ES6 Promise 异步操作

    最近越来越喜欢与大家进行资源分享了,并且及时的同步到自己的园子内,为什么呢? 一.小插曲(气氛搞起) 在上个月末,由于领导的高度重视(haha,这个高度是有多高呢,185就好了),走进了公司骨干员工的 ...

  5. 微信小程序Http高级封装 es6 promise

    公司突然要开放微信小程序,持续蒙蔽的我还不知道小程序是个什么玩意. 于是上网查了一下,就开始着手开发..... 首先开发客户端的东西,都有个共同点,那就是  数据请求! 看了下小程序的请求方式大概和a ...

  6. 解析ES6 Promise

    ES6 Promise 概念之类的,大概读者都应该有所知道,接下来我们直入终点. 先让我们来看看什么是Promise吧,他是一个object,类,arry,function? 首先,学习它的时候应该讲 ...

  7. ES6 Promise(2)

    Promise的兴起,是因为异步方法调用中,往往会出现回调函数一环扣一环的情况.这种情况导致了回调金字塔的出现.不仅代码写起来费劲不美观,而且问题复杂的时候,阅读代码的人也难以理解. db.save( ...

  8. es6 promise 所见

    一.Promise是什么? Promise 是异步编程的一种解决方案: 从语法上讲,promise是一个对象,从它可以获取异步操作的消息:从本意上讲,它是承诺,承诺它过一段时间会给你一个结果. pro ...

  9. ES6 Promise 接口

    构造函数 new Promise(function(resolve, reject){}); 构造函数接受一个函数(executor)作为参数,该函数在返回 Promise 实例之前被调用.函数的两个 ...

  10. ES6 promise学习

    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大. 1.promise是一构造函数,既然是构造函数,那么我们就可以用 new Promise()得到一个p ...

随机推荐

  1. Spring框架-AOP核心

    Spring AOP AOP (Aspect Oriented Programming) 面向切面编程 OOP(Object Oriented Programming)面向对象编程,用对象的思想来完善 ...

  2. SpringCloud 源码学习笔记2——Feign声明式http客户端源码分析

    系列文章目录和关于我 一丶Feign是什么 Feign是一种声明式. 模板化的HTTP客户端.在Spring Cloud中使用Feign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一一样的 ...

  3. Vue学习笔记之Vue-Router

    1. 概述 Vue Router 是 Vue.js 的官方路由.它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举.功能包括: 嵌套路由映射 动态路由选择 模块化.基于组件 ...

  4. vitis笔记1

    安装vitis2021.1 配置环境 添加环境变量 下载包 install 注意:切换到<install_dir>/Vitis//scripts/installLibs.sh,执行指令时候 ...

  5. python去重的几种方法

    from collections import OrderedDict list1 = [1,5,2,1,10] print(list(set(list1))) #[1, 2, 10, 5] 这种方式 ...

  6. JavaScript查找两个节点的最近的一个共同父节点,可以包括节点自身

  7. EMQ X 系统调优和性能压测

    前言 如果使用 EMQ 来承载百万级别的用户连接可以吗?毕竟在 MQTT 官方介绍上说 EMQ X 可以处理千万并发客户端,而 EMQ X 自己官方称 4.x 版本 MQTT 连接压力测试一台 8 核 ...

  8. windows10 远程桌面黑屏

    [计算机配置]-[管理模板]-[Windows组件]-[远程桌面服务]-[远程桌面会话主机]-[远程会话环境]-{为远程桌面连接使用WDDM图形显示驱动程序-设置禁用}

  9. Django views.py 增,删,改

    from django import forms from django.shortcuts import render, redirect from app01 import models # Cr ...

  10. 关于使用C++调用WCF的方法

    因为近期要对接别人的接口,使用的是wcf,因为之前没有使用过wcf,更不了解它,于是在使用的时候出现了很多问题. 下面就记录一下下 在调用方法之前,我们一般都会拿到一个地址,http://xxxxxx ...