当后续的Promise需要用到之前的Promise的处理结果时,需要Promise的串联
Promise对象中,无论是then方法还是catch方法,**它们都具有返回值,返回的是一个全新的Promise对象**,它的状态满足下面的规则
1. 如果当前的Promise**是未决的,得到的新的Promise是挂起状态
2. 如果当前的Pro**mise是已决的,会运行响应的后续处理函数,并将后续处理函数的结果(返回值)作为resolved状态数据,应用到新的Promise中;如果后续处理函数发生错误,则把返回值作为rejected状态数据,应用到新的Promise中。
后续的Promise一定会等到**前面的Promise有了后续处理结果后,才会变成已决状态
3.如果前面的Promise的后续处理,返回的是一个Promise,则返回的新的Promise状态和后续处理返回的Promise状态保持一致。

示例1

  1. const pro = new Promise ((resolve,reject) =>{
  2. })
  3. const pro2 = pro.then(value =>{
  4. return value;
  5. })
  6. pro2.then(value =>{
  7. console.log(1)
  8. })

当其 unsettled阶段为pending状态 说明此时还没结果,所以后面的settled阶段是不会执行的,后面在得到新的promise也会是pending状态

示例2

如果当前的Pro**mise是已决的,会运行响应的后续处理函数,并将后续处理函数的结果(返回值)作为resolved状态数据,应用到新的Promise中;如果后续处理函数发生错误,则把返回值作为rejected状态数据,应用到新的Promise中。**

  1. const pro = new Promise((resolve,reject) =>{
  2. resolve(1)
  3. })
  4. const pro2 = pro.then(value =>{
  5. throw 2
  6. })
  7. pro2.then(value => console.log(value),err => console.log(err))

image.png
pro.then进入啦resolved状态,但是内部代码报错那吗pro2就会接受错误信息进入rejected状态

  1. const pro = new Promise((resolve,reject) =>{
  2. throw 2
  3. })
  4. console.log(pro)
  5. const pro2 = pro.then(value =>{
  6. // throw 2
  7. },err => err * 2 )
  8. pro2.then(value => console.log(value),err => console.log(err * 2 ))

image.png
如上面代码,pro在unsettled阶发送需错误信息 但是 pro在rejected状态并没抛出错误,而是进行运算,那这样就是是后续代码没有出现错误,pro2进入resolved 状态,这说明新的promise 进入那种状态时看它的上一个promise后续处理函数是否出错,没出错那就接受resolved状态数据,反之就接受rejected状态数据

示例3

如果前面的Promise的后续处理,返回的**是一个Promise,则返回的新的Promise状态和后续处理返回的Promise状态保持一致
注意then方法与catch放发返回的时promise对象 ,此处说的是返回一个promise**

  1. const pro = new Promise((resolve,reject)=>{
  2. resolve(1)
  3. })
  4. const pro2 = new Promise((resolve,reject)=>{
  5. resolve(2)
  6. })
  7. const pro3 = pro.then(value =>{
  8. //返回一个promise
  9. return pro2;
  10. })
  11. pro3.then(value =>{
  12. console.log(value) // 结果为 2
  13. })

image.png

示例4

  1. const pro = new Promise((resolve,reject)=>{
  2. resolve(1)
  3. })
  4. pro.then(value =>{
  5. return 1
  6. }).then(value =>{
  7. value = 2
  8. //函数默认返回值为unfinished
  9. }).then(value =>{
  10. console.log(value) //结果为unfinished
  11. }

image.png
此代码中pro的第二个处理函数并没有设置返回值,函数将其默认值unfinished返回,而pro的第三个处理函数却接受的unfinished的值

案例1

回调地狱

ajax.js

  1. <script src="./ajax.js"></script>
  2. <!-- 获取李华所在班级的老师的信息 -->
  3. <script>
  4. ajax({
  5. url: "./data/students.json?name=李华",
  6. success: function (data) {
  7. console.log(data)
  8. for (let i = 0; i < data.length; i++) {
  9. if (data[i].name === '李华') {
  10. const cid = data[i].classId;
  11. ajax({
  12. url: "./data/classes.json?id=" + cid,
  13. success(data) {
  14. console.log(data)
  15. for (let j = 0; j < data.length; j++) {
  16. if (data[j].id === cid) {
  17. const tid = data[j].teacherId;
  18. ajax({
  19. url: "./data/teachers.json?id=" + tid,
  20. success(data) {
  21. for (let i = 0; i < data.length; i++) {
  22. if (data[i].id === tid) {
  23. console.log(data[i])
  24. }
  25. }
  26. }
  27. })
  28. }
  29. }
  30. }
  31. })
  32. }
  33. }
  34. }
  35. })
  36. </script>

promise

  1. // 辅助函数,把传进来的对象拼接成url的字符串
  2. function toData(obj) {
  3. if (obj === null) {
  4. return obj;
  5. }
  6. let arr = [];
  7. for (let i in obj) {
  8. let str = i + "=" + obj[i];
  9. arr.push(str);
  10. }
  11. return arr.join("&");
  12. }
  13. // 封装Ajax
  14. function ajax(obj) {
  15. return new Promise((resolve, reject) => {
  16. //指定提交方式的默认值
  17. obj.type = obj.type || "get";
  18. //设置是否异步,默认为true(异步)
  19. obj.async = obj.async || true;
  20. //设置数据的默认值
  21. obj.data = obj.data || null;
  22. // 根据不同的浏览器创建XHR对象
  23. let xhr = null;
  24. if (window.XMLHttpRequest) {
  25. // 非IE浏览器
  26. xhr = new XMLHttpRequest();
  27. } else {
  28. // IE浏览器
  29. xhr = new ActiveXObject("Microsoft.XMLHTTP");
  30. }
  31. // 区分get和post,发送HTTP请求
  32. if (obj.type === "post") {
  33. xhr.open(obj.type, obj.url, obj.async);
  34. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  35. let data = toData(obj.data);
  36. xhr.send(data);
  37. } else {
  38. let url = obj.url + "?" + toData(obj.data);
  39. xhr.open(obj.type, url, obj.async);
  40. xhr.send();
  41. }
  42. // 接收返回过来的数据
  43. xhr.onreadystatechange = function () {
  44. if (xhr.readyState === 4) {
  45. if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
  46. resolve(JSON.parse(xhr.responseText))
  47. } else {
  48. reject(xhr.status)
  49. }
  50. }
  51. }
  52. })
  53. }
  54. // 开始查询
  55. const pro = ajax({
  56. url: './data/students.json'
  57. })
  58. pro.then(value => {
  59. for (let i = 0; i < value.length; i++) {
  60. if (value[i].name === '李华') {
  61. return value[i].classId
  62. }
  63. }
  64. }).then(cid => {
  65. return ajax({
  66. url: "./data/classes.json?id=" + cid,
  67. }).then(value => {
  68. for (let i = 0; i < value.length; i++) {
  69. if (value[i].id === cid) {
  70. return value[i].teacherId
  71. }
  72. }
  73. })
  74. }).then(tid => {
  75. return ajax({
  76. url: "./data/teachers.json?id=" + tid,
  77. }).then(value =>{
  78. for (let i = 0; i < value.length; i++) {
  79. if(value[i].id === tid){
  80. console.log(value[i])
  81. }
  82. }
  83. })
  84. })

从上面两个代码中es6之前的回调地狱的代码及其不易看懂,毕竟嵌套太多观察起来很不容易,es6的promise,并不有减少代码而是消除回调地狱,不会让他无限回调下去而是将回调变得可以控制,把它每一块都分开啦,每一个then方法处理一个步骤处理完后交个下一个promise处理 以此形成一个串联关系