Promise 笔记

简介

1. 什么是Promise?
  • Promise是JS中进行异步编程的新解决方案(fs 文件操作,数据库操作,AJAX,定时器)
  • Promise是一个构造函数,promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
2. Promise的优点
  • 指定回调函数的方式更加灵活
  • 支持链式调用,可以解决回调地狱问题

回调地狱

  • 含义:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件
  • 缺点:不便于阅读;不便于异常处理

使用

简单使用

<h1>Promise初体验</h1>
<hr />
<button id="btn">点我抽奖</button>
<script>
  //生成随机数
  function rand(m, n) {
    return Math.ceil(Math.random() * (n - m + 1)) + m - 1;
  }
  document.getElementById("btn").onclick = function () {
    const p = new Promise((resolve, reject) => {
      setTimeout(() => {
        let n = rand(1, 100);
        if (n <= 30) {
          resolve(n); // 将Promise对象的状态设置为 成功
        } else {
          reject(n); // 将Promise对象的状态设置为 失败
        }
      }, 1000);
    });
    // 调用then方法
    p.then(
      // 成功回调
      (value) => {
        alert("中奖了!您的中奖数字为:" + value);
      },
      // 失败回调
      (reason) => {
        alert("啥也没有,您的号码为:" + reason);
      }
    );
  };
</script>

fs文件读取

const fs = require("fs");

function mineReadFile(path) {
  return new Promise((resolve, reject) => {
    fs.readFile(path, (err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
}

mineReadFile("./note.txt").then(
  (value) => {
    console.log(value.toString());
  },
  (reason) => {
    console.log(reason);
  }
);
const fs = require("fs");
const util = require("util");
let mineReadFile = util.promisify(fs.readFile);

mineReadFile("./note.txt").then(
  (value) => {
    console.log(value.toString());
  },
  (reason) => {
    console.log(reason);
  }
);

AJAX请求

<h1>Promise 封装 AJAX</h1>
<hr />
<button id="btn">点我发送 AJAX请求</button>
<script>
  document.getElementById("btn").onclick = function () {
    const p = new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.open("GET", "https://api.apiopen.top/getJoke");
      xhr.send();
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status >= 200 && xhr.status < 300) {
            resolve(xhr.response);
          } else {
            reject(xhr.status);
          }
        }
      };
    });
    p.then(
      (value) => {
        console.log(value);
      },
      (reason) => {
        console.log(reason);
      }
    );
  };
</script>

Promise的状态改变

  • Promise的状态指的是Promise实例对象中的一个属性
  • 改变只有两种:pending 变为 resolved / fullfilled 或者是 pending 变为 rejected
  • pending 是初始默认值,表示未决定的
  • 一个promise对象只能改变一次,无论变为成功还是失败,都会有一个结果数据

Promise对象的值

  • Promise实例对象中的另一个属性,保存的是异步任务成功或失败的结果
  • resolve 和 reject 函数才可以修改这个值

Promise的基本流程

在这里插入图片描述

Promise 的 API

Promise()

const p = new Promise((resolve, reject) => {})
/*
executor 函数:(resolve, reject) => {} 也叫执行器函数
resolve 函数:内部定义成功时调用的函数 value => {}
reject 函数:内部定义失败时调用的函数 reason => {}
说明:executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行
*/

Promise.prototype.then(onResolved, onRejected) => {}

p.then(onResolved, onRejected) => {}
/*
onResolved 函数:成功的回调函数 value => {}
onRejected 函数:失败的回调函数 reason => {}
说明:指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调,返回一个新的 promise 对象
*/

Promise.prototype.catch(onRejected) => {}

const p = new Promise((resolve, reject) => {
  reject("error!dudu!");
});
p.catch((reason) => {
  console.log(reason); // error!dudu!
});

Promise.resolve()

// 如果传入的参数为 非promise类型的对象,返回的结果为成功promise对象
Promise.resolve(1208).then((value) => {
  console.log(value); // 1208
});
// 如果传入的参数为 promise类型的对象,则参数的结果决定了 resolve 的结果,如果参数成功结果就是成功
Promise.resolve(p).then(
  (value) => {
    console.log("成功了~", value);
  },
  (reason) => {
    console.log("失败了~", reason);
  }
);

Promise.reject()

// 不管参数是什么,返回都是一个失败的promise对象,对象的值就是参数的值
Promise.reject(1208).catch((reason) => {
  console.log(reason); // 1208
});
Promise.reject(
  new Promise((resolve, reject) => {
    resolve("success!dudu!");
  })
).catch((reason) => {
  console.log(reason); // Promise { 'success!dudu!' } 成功的promise对象
});

Promise.all()

const p = new Promise((resolve, reject) => {
  reject("error!dudu!");
});
const p0 = new Promise((resolve, reject) => {
  reject("defeat!dudu!");
});
const p2 = new Promise((resolve, reject) => {
  resolve("success!dudu!");
});
const p3 = new Promise((resolve, reject) => {
  resolve("victory!dudu!");
});
// 返回的promise对象只有当数组中的所有对象都成功时才成功
Promise.all([p, p0, p2]).then(
  (value) => {
    console.log("成功了~", value);
  },
  (reason) => {
    console.log("失败了~", reason); // 失败了~ error!dudu! 失败的返回值是数组中第一个失败对象的值
  }
);
Promise.all([p3, p2]).then(
  (value) => {
    console.log("成功了~", value); // 成功了~ [ 'victory!dudu!', 'success!dudu!' ] 成功的值所有对象组成的数组
  },
  (reason) => {
    console.log("失败了~", reason);
  }
);

Promise.race()

const p = new Promise((resolve, reject) => {
  reject("error!dudu!");
});
const p2 = new Promise((resolve, reject) => {
  resolve("success!dudu!");
});
// 返回的promise对象与数组中先得到结果的promise对象相同
Promise.race([p, p2]).then(
  (value) => {
    console.log("成功了~", value);
  },
  (reason) => {
    console.log("失败了~", reason);
  }
);

一些关键问题

1. 修改Promise对象状态的方法

调用 resolve方法将状态从 pending 修改为 resolved

const p = new Promise((resolve, reject) => {
  resolve("dudu");
});
console.log(p);

调用 reject方法将状态从 pending 修改为 rejected

const p = new Promise((resolve, reject) => {
  reject("dudu");
});
console.log(p);

通过抛出错误的方式,将状态从 pending 修改为 rejected

const p = new Promise((resolve, reject) => {
  throw "dudu";
});
console.log(p);
2. 多个回调的执行

当Promise对象的状态改变时,对应的多个回调都会执行

const p = new Promise((resolve, reject) => {
  resolve("dudu");
});
// 下面指定的两个回调都会执行
p.then((value) => {
  console.log("1.成功了...", value);
});
p.then((value) => {
  console.log("2.成功了...", value);
});
3. 改变promise状态和指定回调函数的先后顺序

先改变状态再指定回调:使用同步代码改变状态 或 回调也在异步中指定

const p = new Promise((resolve, reject) => {
  resolve("dudu");
});
p.then(
  (value) => {
    console.log("成功了...", value);
  },
  (reason) => {
    console.log("失败了...", reason);
  }
);

先指定回调再改变状态:使用异步代码改变状态

const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("zhou");
  }, 1000);
});
p.then(
  (value) => {
    console.log("成功了...", value);
  },
  (reason) => {
    console.log("失败了...", reason);
  }
);
4. promise.then() 返回的新 promise 的结果状态
const p = new Promise((resolve, reject) => {
  resolve("zhou");
});
/*
result 是一个promise对象,它的值由回调方法的结果决定
1. 如果抛出异常,result的状态为失败,值为回调throw的内容
2. 如果返回结果为非promise类型的对象,result的状态为成功,值为回调返回的值
3. 如果返回结果为promise类型的对象,result由回调中返回的对象来决定
*/
const result = p.then((value) => {
  console.log("成功了...", value);
  // throw "zh  ou";
  // return 123;
  return new Promise((resolve, reject) => {
    // resolve("我在回调里成功了");
    reject("我在回调里失败了");
  });
});
console.log(result);
5. promise串联多个操作任务

由于promise的then方法返回的还是promise对象,可以进行链式调用

const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("dudu");
  }, 1000);
});
p.then((value) => {
  console.log("成功了...", value);
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("dududu");
    }, 1000);
  });
}).then((value) => {
  console.log("成功了...", value);
});
6. promise异常穿透

当使用 promise 的 then 链式调用时,可以在最后指定失败的回调,前面的任何操作出了异常,都会传到最后失败的回调中处理

const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("dudu");
    // reject("dudududududu");
  }, 1000);
});
p.then((value) => {
  console.log("成功了...", value);
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // resolve("dududu");
      reject("dudududududu");
    }, 1000);
  });
})
  .then((value) => {
    console.log("成功了...", value);
  })
  .then((value) => {
    console.log("成功了...", value);
  })
  .catch((reason) => {
    console.log(reason);
  });
7. 中断Promise链

含义:当使用promise的then链式调用时,在中间间断,不再调用后面的回调函数
方式:在回调函数中返回一个pending状态的promise对象

const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("dudu");
  }, 1000);
});
p.then((value) => {
  console.log("成功了...", value);
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("dududu");
    }, 1000);
  });
})
  .then((value) => {
    console.log("成功了...", value);
    // 返回一个pending状态的promise对象
    return new Promise(() => {});
  })
  .then((value) => {
    console.log("成功了...", value);
  })
  .catch((reason) => {
    console.log(reason);
  });

async 和 await

1. async 函数
  • 函数的返回值为promise对象
  • promise 对象的结果由 async 函数执行的返回值决定
// 和then方法返回值的规则相同
async function fn() {
  // return 123;
  // return new Promise((resolve, reject) => {
  //   reject("OK");
  // });
  throw "error";
}
console.log(fn());
2. await 表达式
  • await 右侧的表达式一般为 promise 对象,但也可以使其他的值
  • 如果是 promise 对象,await 返回的是 promise 成功的值
  • 如果是其他值,直接将此值作为 await 的返回值
async function fn() {
  // let r1 = await new Promise((resolve, reject) => {
  //   resolve("OK");
  // });
  // let r2 = await 200;
  // console.log(r2);
  try {
    let r3 = await new Promise((resolve, reject) => {
      reject("error");
    });
  } catch (error) {
    console.log(error);
  }
}
fn();

注意:

  • await 必须写在 async 函数中,但 async 函数中可以没有 await
  • 如果 await 的 promise 失败了,就会抛出异常,需要通过 try…catch 捕获处理
3. 两个实例

读取三个文件

const fs = require("fs");
const util = require("util");
let mineReadFile = util.promisify(fs.readFile);

async function main() {
  try {
    let data1 = await mineReadFile("./note.txt");
    let data2 = await mineReadFile("./note.txt");
    let data3 = await mineReadFile("./note.txt");
    console.log(data1, data2, data3);
  } catch (error) {
    console.log(error);
  }
}

main();

发送AJAX请求

async function main() {
  try {
    let data = await axios({
      method: "GET",
      url: "https://api.apiopen.top/getJoke",
    });
    console.log(data);
  } catch (error) {
    console.log(error);
  }
}

main();

可以省略回调函数,书写比较简洁清晰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值