一、promise介绍和基本使用
一.基本介绍
概念上:promise是一门新的技术,E6中新出的规范,是用来解决JS中进行异步编程的新的解决方案(旧的方案是单纯的使用回调函数,会造成回调地狱)
表达上:是回调函数的形式,主要通过promise对象用来封装一个异步操作并可以获取其成功和失败的结果值
优势:
1.指定回调函数的方式更加灵活
旧的:必须在启动异步任务之前指定回调函数
promise:启动异步任务》返回promise对象》给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个)
2.支持链式调用,可以解决回调地狱问题
旧的:回调地狱:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套函数的回调执行的条件
promise:链式回调
扩展:异步编程
1.fs 文件操作 (node.js下的一个模块,可以对计算机中的磁盘进行读写操作)
require(“fs”).readfile(“./index.html”),(err,data)=>{} //异步函数回调
2.数据库操作
3.AJAX网络请求
4.定时器
二、基本使用
2.1promise基本使用
<div class="div">点击抽奖</div>
<script>
// 随机函数
var random = function (m, n) {
return Math.ceil(Math.random() * (n - m + 1) + m - 1)
}
// 获取页面的元素
let btn = document.querySelector(".div")
// 绑定单机事件
btn.addEventListener("click", function () { //点击事件click
// console.log("hhh");
// 1秒后执行回调
// 1.普通的回调函数
setTimeout(() => {
// 从1开始生成随机数取值区间为1000
let n = random(1,100)
if(n<=30){
alert("中奖啦")
}else {
alert("再接再厉")
}
}, 1000);
// 2.promise
// reslove 异步任务成功解决 都是函数类型的数据
// reject 异步任务失败拒绝 都是函数类型的数据
let p = new Promise((reslove, reject) => { //实例化一个promise对象时里面接收的一个函数类型的参数
// 里面包裹一个异步函数
setTimeout(() => {
// 从1开始生成随机数取值区间为1000
let n = random(1, 100)
if (n <= 30) {
// 将n当成结果值传递给两个函数后面的then方法就会接收到结果值
// 成功的时候调用
reslove(n) //调用后可以将promise对象(p)的状态设置为成功
} else {
reject(n) //调用后可以将promise对象(p)的状态设置为失败
}
}, 1000);
})
// 调用then方法(两个回调函数) 第一个成功的回调
p.then((value) => {
alert("中奖啦,中奖数字为"+value)
}, (reason) => { //第二个失败的回调
alert("再接再厉"+ reason)
})
})
</script>
2.2promise封装fs读取文件的操作
//1.基本操作
// node.js中
// 1.引入fs
const fs = require('fs')
// fs中有一个方法是readFil读取文件,一个是读取文件的路径,第二个是成功和失败的回调
fs.readFile('./resource/content', (err, data) => {
// 如果出错抛出错误
if (err) throw err
// 没有出错输出文件
console.log(data);
})
// promise封装
const p = new Promise((resolve, reject) => {
fs.readFile('./resource/content', (err, data) => {
// 如果出错抛出错误 记住得把结果值传入进去
if (err) reject(err)
// 没有出错输出文件
resolve(data)
})
})
p.then(value=> {
console.log(value.toString());
},reason => {
throw reason
})
//2.封装一个函数
// 封装一个读取fs文件的函数(promise处理异步)
// 参数:路径:path
// 返回值promise对象
function mineReadFile(path) {
return new Promise((resolve, reject) => {
require("fs").readFile(path, (err, data) => {
if(err) reject(err)
resolve(data)
})
})
// 因为上面额函数返回值就是promise,因此可以直接在函数的返回值进行使用then方法
mineReadFile('./resource/content').then((value)=>{
console.log(value);
},(reason)=>{
console.log(reason);
})
//3.node.js内部函数 util.promisify(original):传入一个遵循常见的错误优先的回调函数,并返回一个promise的版本
let util = require("util")
let fs = require('fs')
// 返回一个新的函数返回的结果就是promise对象
let mineReadFile = util.promisify(fs.readFile)
// 因为上面额函数返回值就是promise,因此可以直接在函数的返回值进行使用then方法
mineReadFile('./resource/content').then((value)=>{
console.log(value);
},(reason)=>{
console.log(reason);
})
2.3promise封装ajax
//1.基本使用
<div class="btn">点击发送请求</div>
<script>
//接口地址:http://api.a
let btn = document.querySelector(".btn")
btn.addEventListener("click", function () {
let p = new Promise((resolve, reject) => {
// 发送ajax请求
// 1.创建对象
const xhr = new XMLHttpRequest()
// 2.初始化请求方式和请求地址
xhr.open("GET", 'http://api.a')
// 3.发送
xhr.send()
// 4.处理响应
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);
})
})
//2.封装一个函数
function senAjax(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.responseText = 'json' //ajax将响应文本转换为json格式
xhr.open('GET', url)
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) { //为4是所有结果都返回时的一个状态
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response)
} else {
reject(xhr.status)
}
}
}
})
}
senAjax('http:/nn').then((value) => {
console.log(value);
}, (reason) => {
console.log(reason);
</script>
二、promise的API
1、promiseState:promise对象中状态属性
- pending 未决定的
- resloved / fullfilled 成功
- rejected 失败
改变状态只有这两种(而且这个状态只能改变一次) - pending -> resloved (数据结果一般为value)
- pending->rejected (数据结果一般为reason)
2、promiseResult:promise对象的值
概念:保存的是异步任务保存失败或者成功的结果
- resloved
- rejected 这两个函数进行更改,然后通过then方法就可以对值进行操作
3、promise构造函数:promise(excutor){}
- excutor函数:执行器(resolve,reject)=>{} 立即执行是同步的
- resolve 内部定义成功时调用的函数 value=>{}
- reject 内部定义失败时调用的函数 reason =>{}
4、Promise.prototype.then 方法:(onResoved,onRejected)=>{}
- 指定用于得到value成功的回调。失败的reason的失败回调,返回一个新的promise对象
5、Promise.prototype.catch方法:(onRejected)=>{}
- then()的语法糖, 相当于: then(undefined, onRejected)
6.Promise.resolve 方法: (value) => {}
- value: 成功的数据或 promise 对象
- 说明 : 返回一个成功/失败的 promise 对象
let p = Promise.resolve(123)
console.log(p); //返回一个成功或者失败的promise对象 失败只由传入是promise的失败决定
7.Promise.reject 方法: (reason) => {}
- reason: 失败的原因
- 说明 : 返回一个失败的 promise 对象
let p = Promise.reject(123)
let p1 = Promise.reject(new Promise((resolve,reject)=>{
resolve("成功")
}))
console.log(p1); //返回一个失败的promise对象 正常数值也是失败,传入的是promise对象也是失败,但是会存储传入promise的数值状态
8.Promise.all 方法: (promises) => {}
- promises: 包含 n 个 promise 的数组
- 说明: 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就
直接失败
9.Promise.race 方法: (promises) => {}
- promises: 包含 n 个 promise 的数组
- 说明 : 返回一个新的 promise, 第一个完成的 p
三、promise的关键问题
- 如何改变 promise 的状态?
(1) resolve(value): 如果当前是 pendding 就会变为 resolved
(2) reject(reason): 如果当前是 pendding 就会变为 rejected
(3) 抛出异常: 如果当前是 pendding 就会变为 rejected
- 一个 promise 指定多个成功/失败回调函数, 都会调用吗?
当 promise 改变为对应状态时都会调用,并且不会覆盖
-
改变 promise 状态和指定回调函数谁先谁后?
(1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
(2) 如何先改状态再指定回调?
1 在执行器中直接调用 resolve()/reject()
2 延迟更长时间才调用 then()
(3) 什么时候才能得到数据?
1 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
2 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据 -
promise.then()返回的新 promise 的结果状态由什么决定?
(1) 简单表达: 由 then()指定的回调函数执行的结果决定,也就是then指定的回调函数返回结果决定(undefind等只要不是新的promise的失败回调都是成功)
(2) 详细表达:
1 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
2 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
3 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
- promise 如何串连多个操作任务?
(1) promise 的 then()返回一个新的 promise, 可以开成 then()的链式调用
(2) 通过 then 的链式调用串连多个同步/异步任务
- promise 异常传透?
(1) 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调, (2) 前面任何操作出了异常, 都会传到最后失败的回调中处理
- 中断 promise 链?
(1) 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
(2) 办法: 在回调函数中返回一个 pendding 状态的 promise 对象
四、promise自定义封装
1.构造函数封装
//声明构造函数
function Promise(executor){
//添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
//声明属性
this.callbacks = [];
//保存实例对象的 this 的值
const self = this;// self _this that
//resolve 函数
function resolve(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';// resolved
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
//调用成功的回调函数
setTimeout(() => {
self.callbacks.forEach(item => {
item.onResolved(data);
});
});
}
//reject 函数
function reject(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'rejected';//
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
//执行失败的回调
setTimeout(() => {
self.callbacks.forEach(item => {
item.onRejected(data);
});
});
}
try{
//同步调用『执行器函数』
executor(resolve, reject);
}catch(e){
//修改 promise 对象状态为『失败』
reject(e);
}
}
//添加 then 方法
Promise.prototype.then = function(onResolved, onRejected){
const self = this;
//判断回调函数参数
if(typeof onRejected !== 'function'){
onRejected = reason => {
throw reason;
}
}
if(typeof onResolved !== 'function'){
onResolved = value => value;
//value => { return value};
}
return new Promise((resolve, reject) => {
//封装函数
function callback(type){
try{
//获取回调函数的执行结果
let result = type(self.PromiseResult);
//判断
if(result instanceof Promise){
//如果是 Promise 类型的对象
result.then(v => {
resolve(v);
}, r=>{
reject(r);
})
}else{
//结果的对象状态为『成功』
resolve(result);
}
}catch(e){
reject(e);
}
}
//调用回调函数 PromiseState
if(this.PromiseState === 'fulfilled'){
setTimeout(() => {
callback(onResolved);
});
}
if(this.PromiseState === 'rejected'){
setTimeout(() => {
callback(onRejected);
});
}
//判断 pending 状态
if(this.PromiseState === 'pending'){
//保存回调函数
this.callbacks.push({
onResolved: function(){
callback(onResolved);
},
onRejected: function(){
callback(onRejected);
}
});
}
})
}
//添加 catch 方法
Promise.prototype.catch = function(onRejected){
return this.then(undefined, onRejected);
}
//添加 resolve 方法
Promise.resolve = function(value){
//返回promise对象
return new Promise((resolve, reject) => {
if(value instanceof Promise){
value.then(v=>{
resolve(v);
}, r=>{
reject(r);
})
}else{
//状态设置为成功
resolve(value);
}
});
}
//添加 reject 方法
Promise.reject = function(reason){
return new Promise((resolve, reject)=>{
reject(reason);
});
}
//添加 all 方法
Promise.all = function(promises){
//返回结果为promise对象
return new Promise((resolve, reject) => {
//声明变量
let count = 0;
let arr = [];
//遍历
for(let i=0;i<promises.length;i++){
//
promises[i].then(v => {
//得知对象的状态是成功
//每个promise对象 都成功
count++;
//将当前promise对象成功的结果 存入到数组中
arr[i] = v;
//判断
if(count === promises.length){
//修改状态
resolve(arr);
}
}, r => {
reject(r);
});
}
});
}
//添加 race 方法
Promise.race = function(promises){
return new Promise((resolve, reject) => {
for(let i=0;i<promises.length;i++){
promises[i].then(v => {
//修改返回对象的状态为 『成功』
resolve(v);
},r=>{
//修改返回对象的状态为 『失败』
reject(r);
})
}
});
}
2.类的封装
class Promise{
//构造方法
constructor(executor){
//添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
//声明属性
this.callbacks = [];
//保存实例对象的 this 的值
const self = this;// self _this that
//resolve 函数
function resolve(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';// resolved
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
//调用成功的回调函数
setTimeout(() => {
self.callbacks.forEach(item => {
item.onResolved(data);
});
});
}
//reject 函数
function reject(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'rejected';//
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
//执行失败的回调
setTimeout(() => {
self.callbacks.forEach(item => {
item.onRejected(data);
});
});
}
try{
//同步调用『执行器函数』
executor(resolve, reject);
}catch(e){
//修改 promise 对象状态为『失败』
reject(e);
}
}
//then 方法封装
then(onResolved,onRejected){
const self = this;
//判断回调函数参数
if(typeof onRejected !== 'function'){
onRejected = reason => {
throw reason;
}
}
if(typeof onResolved !== 'function'){
onResolved = value => value;
//value => { return value};
}
return new Promise((resolve, reject) => {
//封装函数
function callback(type){
try{
//获取回调函数的执行结果
let result = type(self.PromiseResult);
//判断
if(result instanceof Promise){
//如果是 Promise 类型的对象
result.then(v => {
resolve(v);
}, r=>{
reject(r);
})
}else{
//结果的对象状态为『成功』
resolve(result);
}
}catch(e){
reject(e);
}
}
//调用回调函数 PromiseState
if(this.PromiseState === 'fulfilled'){
setTimeout(() => {
callback(onResolved);
});
}
if(this.PromiseState === 'rejected'){
setTimeout(() => {
callback(onRejected);
});
}
//判断 pending 状态
if(this.PromiseState === 'pending'){
//保存回调函数
this.callbacks.push({
onResolved: function(){
callback(onResolved);
},
onRejected: function(){
callback(onRejected);
}
});
}
})
}
//catch 方法
catch(onRejected){
return this.then(undefined, onRejected);
}
//添加 resolve 方法
static resolve(value){
//返回promise对象
return new Promise((resolve, reject) => {
if(value instanceof Promise){
value.then(v=>{
resolve(v);
}, r=>{
reject(r);
})
}else{
//状态设置为成功
resolve(value);
}
});
}
//添加 reject 方法
static reject(reason){
return new Promise((resolve, reject)=>{
reject(reason);
});
}
//添加 all 方法
static all(promises){
//返回结果为promise对象
return new Promise((resolve, reject) => {
//声明变量
let count = 0;
let arr = [];
//遍历
for(let i=0;i<promises.length;i++){
//
promises[i].then(v => {
//得知对象的状态是成功
//每个promise对象 都成功
count++;
//将当前promise对象成功的结果 存入到数组中
arr[i] = v;
//判断
if(count === promises.length){
//修改状态
resolve(arr);
}
}, r => {
reject(r);
});
}
});
}
//添加 race 方法
static race (promises){
return new Promise((resolve, reject) => {
for(let i=0;i<promises.length;i++){
promises[i].then(v => {
//修改返回对象的状态为 『成功』
resolve(v);
},r=>{
//修改返回对象的状态为 『失败』
reject(r);
})
}
});
}
}
五、async与await
async函数:
1.函数的返回值为promise对象
2.promise对象的结果由async函数执行的返回值决定
await表达式
1.await右侧的表达式一般为promise对象,但也可以是其它的值,如果表达式是其它值,直接将此值作为await的返回值
2.如果表达式是promise对象,await返回的是promise成功的值
注意:
1.await必须写在async函数中,但async函数中可以没有await
2.如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理