Promise深入剖析

Promise深入剖析

一、前提须知:

同步异步:

  • 现实生活中同步与异步操作
    1. 同步:烧水10分钟+准备茶叶3分钟 一共花了13分钟
    2. 异步:在烧水得10分钟里面去准备茶叶 一共花了10分钟
  • 软件世界中
    1. 同步:当一个操作开始执行、主程序需要等它完成、才能继续下一步操作(一般是下一步得程序需要上一步的数据)
    2. 异步:当一个操作开始执行后、主程序不会等它完成、直接就会执行下一步。(此时该操作可以跟主程序同时并发执行)

回调函数:

  1. 将函数callback作为参数传入给函数fun、在函数fun中以形参方式进行调用,函数call就称为回调函数。

    /* 回调函数 */
    function callback(){
    console.log('我是一个回调函数');
    }
    /* 普通函数 */
    function fun(cb){
    cb() //作为形参传进来、然后将形参执行
    }
    // 将回调函数作为参数,传进去
    fun(callback) //我是一个回调函数
    
  2. 回调地狱()

    image-20220813162703732

  3. 艺术图展示

    image-20220813162823819

  4. 回调地狱、其实就是回调函数嵌套过多导致的

    image-20220813163018432

二、Promise的介绍

介绍:

  1. Promise 是异步编程的一种更优雅的解决方案,比传统的解决方案——回调函数——更合理和更强大。
  2. Promise就是对异步操作的封装、封装异步文件读写
  3. 就是一个构造函数、通过new关键字实例化对象、接受函数为参数

特点:

  1. 对象的状态不受外界影响、Promise代表一个异步操作、有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
  2. 只有异步操作的结果、可以决定当前是哪一个状态、其他的操作都无法改变这个状态。
  3. 一旦状态改变、就不会再变、任何时候都可以得到这个结果。Promise对象状态改变只有两种可能
    • 从pending变为fulfilled状态
    • 从pending变为rejected状态
    • 只要发生改变就定型了(ps:一诺千金真男人)
  4. image-20220813165233082

参数梳理:

Promise()

new Promise((resolve,reject)=>{})
  1. Promise()里面是一个箭头函数、作为参数
  2. 参数函数里面有两个参数
    • resolve:成功函数
    • reject:失败函数

Promise实例

const p1 = new Promise((resolve, reject) => {
    reject('我是失败结果')// 调用函数, 使当前Promise对象的状态改成rejected
        })

image-20220813170900014

  1. Promise实例有两个属性

    • PromiseState:状态

    • PromiseResult:结果

  2. Promise的状态

    1. pending(等待)
    2. fulfiled (满足)
    3. rejected (拒绝)
  3. Promise状态改变

    1. resolve(): 调用函数, 使当前Promise对象的状态改成fulFilled
    2. reject(): 调用函数,使当前Promise对象状态改成rejected
    3. 想要输出的结果都在resolve()、reject()里面去写
    4. 注意事项:
      1. Promise状态的改变是一次性的,改了就定死了
      2. 如果不改变Promise状态,那就一直是pending,不会运行其他结果、一直持续那个等待的那个状态。

三、Promise的方法

then方法(搞定它你就懂了

  • 两个参数
    1. 第一个成功回调函数(fulfiled 状态执行)
    2. 第二个失败回调函数(rejected 状态执行)
    3. 注意1:只能通过resolve,reject改变Promise的状态值,从而在then方法里、通过根据状态值来决定执行第一个回调函数、还是执行第二个回调函数(大白话)
  • 返回值
    • 是一个Promise对象
实例1:不带参数的执行

白话理解:这个promise就是一个标准好男人、只要他结婚了就坚决不会去外面找小三。(先入为主、后面的代码不起作用)

const p = new Promise((resolve,reject)=>{
    // 通过调用resolve、传递参数当前Promise对象的结果
    reject('这个是失败的结果')  //将PromiseState状态改为rejected
    resolve('这个是成功的结果') //状态只能先入为主、这个改变不了
})

/* .then方法函数
    参数:
        1、两个参数都是函数
        2、第一个参数是成功回调函数
        3、第二个参数是失败回调函数
    返回值:
        是一个Promise对象
*/
p.then(()=>{
    //当Promise的状态使fulfilled时执行
    console.log('打印我第一个成功函数');
},()=>{
    //当Promise的状态时rejected时, 执行
    console.log('打印我第二个失败函数');
})

console.dir(p);

image-20220814123935394

实例2:带参数的执行

  • 在then方法的参数函数中、通过形参(value)使用Promsie对象的结果(reslove)
const p = new Promise((resolve,reject)=>{
    let obj = {
        name:'zjf',
        age:19
    }
    // 通过调用resolve、传递参数当前Promise对象的结果
    resolve(obj) //传入一个对象
    reject('这个是失败的结果')  //将PromiseState状态改为rejected
})

/* .then方法函数
    参数:
        1、两个参数都是函数
        2、第一个参数是成功回调函数
        3、第二个参数是失败回调函数
    返回值:
        是一个Promise对象
*/
p.then((value)=>{
    //当Promise的状态使fulfilled时执行
    console.log('打印我第一个成功函数');
    console.log(value);
},(error)=>{
    //当Promise的状态时rejected时, 执行
    console.log('打印我第二个失败函数');
})
console.dir(p);

image-20220814125208232

实例3:then方法中的return

  1. 通过resovle(obj)会传值给,then(成功函数)
  2. 成功函数中return(obj2),会传值给下一个then(成功函数)
  3. 成功函数中return(不存在)、会给失败函数的error(result)
  4. 失败函数中return(obj4)还是会传给成功函数
  5. 成功函数中不return,只会执行。并没有传值

结论:

  1. 在then方法中,通过return将返回的Promise实例改为fulfilled状态
  2. 在then方法中,出现代码错误,将返回的Promise实例改为rejected状态

image-20220814134343915

const p = new Promise((resolve,reject)=>{
    let obj = {
        name:'obj',
        age:19
    }
    // 通过调用resolve、传递参数当前Promise对象的结果
    resolve(obj) //传入一个对象
    reject('这个是失败的结果')  //将PromiseState状态改为rejected
})

/* .then方法函数
    参数:
        1、两个参数都是函数
        2、第一个参数是成功回调函数
        3、第二个参数是失败回调函数
    返回值:
        是一个Promise对象
*/
p
/* 第一个then方法
    使用value接受obj的值
    创建一个obj2对象并通过return传值给下一个then
*/
.then((value)=>{
    let obj2 = {
        name:'obj2',
        age:20
    }
    //当Promise的状态使fulfilled时执行
    console.log('打印我第一个then成功函数');
    console.log(value); //打印接受到的obj

    // 在then方法回返回一个新的Promise实例,状态时pending
    return obj2
},(error)=>{
    //当Promise的状态时rejected时, 执行
    console.log('打印我第一个失败函数');
})
/* 
    第二个then方法
    接受obj2的通过return传来的值
        
*/ 
.then((value)=>{
    console.log('打印我第二个then成功函数');
    console.log(value);
    // 返回一个不存在的值
    return obj3
},(error)=>{
    console.log('打印我第二个then失败函数');
    console.log(error);
})

/* 
    第三个then方法
    当接受一个不存在的值(reject)
    使用第二个参数函数接受值
*/
.then((value)=>{
    console.log(value);
},(error)=>{
    let obj4 = {
        name:'obj4',
        age:22
    }
    console.log(error);
    return obj4
})
/* 
    第四个then方法
    当在第二个函数中、创建一个对象
    接受的值还是在第一个函数中接受
*/

.then((value)=>{
    let obj5 = {
        name:'obj5',
        age:33
    }
    console.log(value); //{name: 'obj4', age: 22}
},(error)=>{
    console.log(error);
})
/* 
    第五个then方法
    在第一个函数中、创建一个对象
    但是不return这个值
*/
.then((value)=>{
    console.log('让我看看第五个then成功');
    console.log(value);
},(error)=>{
    console.log('让我看看第五个then失败');
})

实例4:状态没有改变、then方法不会执行

        // 如果Promise的状态改变,then里的方法不会执行
const p = new Promise((resolve, reject) => {
    let a = 1
    console.log('我啥也没干啊');
}).then((value) => {
	console.log("成功")
},(reason) => {
console.log("失败")
})
//我啥也没干啊

catch方法

  • 其实这个方法、就是then方法里面的第二个方法作用一样
  • 但是这个方法可以增加代码的可读性,让你一眼就知道这个方法是干嘛的

参数名:根据官方来,最好形参名定为reason

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

// 思考: catch中的参数函数在什么时候被执行
//  1. 当Promise的状态改为rejcted.被执行
//  2. 当Promise执行过程出现代码错误时,被执行
p.catch((reason => {
console.log("失败", reason) //失败 undefined
}))

优化代码:此段代码是模仿杰哥课堂中的代码

// 封装ajax请求
function getData(url, data = {}){
	return new Promise((resolve, reject) => {
  	$.ajax({
      // 发送请求类型
    	type: "GET",
      url: url,
      data: data,
      success: function (res) {
      	// 修改Promise状态为成功, 修改Promise的结果res
        resolve(res)
      },
      error:function (res) {
      	// 修改Promise的状态为失败,修改Promise的结果res
        reject(res)
      }
    })
  }
}

// 调用函数
getData("data1.json")
  .then((data) => {
  	// console.log(data)
    const { id } = data
    return getData("data2.json", {id})
  })
  .then((data) => {
  	// console.log(data)
    const { usename } = data
    return getData("data3.json", {usename})
  })
  .then((data) => {
  	console.log(data)
  })

四、Promise.all和Promise.race

Promise.all()

  1. 将多个实例组装成一个新实例

  2. 成功的时候返回一个成功的数组

  3. 失败的时候返回最先被reject失败状态的值

let wake = (time) => {
  // 返回一个新的Promise对象
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`${time}后返回成功结果`)
    }, time);
  })
}
// 使用promise去接受
// wake(5).then(
//   (res) => {
//     console.log(res); //5后返回成功结果
//   }
// )

//使用promise.all接受
let p1 = wake(1999);
let p2 = wake(19);
Promise.all([p1, p2])  //返回一个成功的数组
.then(res => {
  console.log('返回一个成功数组:',res); //['1999后返回成功结果', '19后返回成功结果']
  let [res1, res2] = res; //结构赋值
  console.log(res1, res2);
}).catch(err => {
  console.log(err);//放回第一个错误
})

Prmise.race

  1. 将多个实例进行筛选
  2. 多个实例、那个获取的快、不管是成功、还是失败、先到先得。
let wake = (time) => {
  // 返回一个新的Promise对象
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`${time}后返回成功结果`)
    }, time);
  })
}
// 使用promise去接受
// wake(5).then(
//   (res) => {
//     console.log(res); //5后返回成功结果
//   }
// )

//使用promise.all接受
let p1 = wake(1999);
let p2 = wake(19);
Promise.race([p1, p2])  //返回第一个成功的
.then(res => {
  console.log('返回第一个成功的:',res);  //返回第一个成功的: 19后返回成功结果

}).catch(err => {
  console.log(err);
})

五、async、await理解与用法

理解:其实本质就是一个语法糖、ES7提出的基于Promise的解决异步的最终方案。

async:

  1. 加在函数前的修饰符、将一个普通函数变成返回值变为Promise对象、可以在async函数后面直接.then/.catch方法
  2. return一个对象data、相当于 return Promise.resolve(data)
  3. return Promise 得到Promise本身
  4. 函数内部抛出错误、会被then的第二个函数、catch方法捕获到
// 一个普通的函数加上 async
async function fun(){
  let obj = {
    name:'zjf',
    age:18
  }
  return obj
}
// 可以将一个普通函数值接写成返回一个promise
fun()
.then((value)=>{
  console.log('我是then方法'); //结果我是then方法
  console.log(value);    //结果{name: 'zjf', age: 18}
})
.catch((reson)=>{
  console.log('我是reson方法');
  console.log(reson);
})

await:

  1. await也是一个修饰符、只能放在async定义的函数、理解为等待
  2. await修饰Promise对象时如等3秒、只能获取到reslove成功函数的值、且等3秒之后才会执行、继续往下执行
  3. 当出现错误无法捕获、因为await只拿到了resolve成功的、没有reject失败的。
  4. 如果需要捕获错误、只能通过try、catch方法来捕获错误
let p = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve('3000后成功结果')
  },3000)
})

// 一个普通的函数加上 async
async function fun(){
  let obj = {
    name:'zjf',
    age:18
  }
  console.log('我先不等了'); //第一时间就出来了
  let reson = await p
  console.log(reson);    //等到3000后成功结果才出来
}
//执行函数
fun()

在async函数里通过try、catch来获取错误

let p = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject('这是失败结果')
  },3000)
})

// 一个普通的函数加上 async
async function fun(){
  try {
    let obj = {
    name:'zjf',
    age:18
  }
  console.log('我先不等了'); //第一时间就出来了
  let reson = await p
  } catch (error) {
    console.log(error);   //等到3000后成功结果才出来
    //这是失败结果
  }
}
//执行函数
fun()

在函数外面.catch方法

  1. 可以接受reject函数里面的值
  2. 无法接受其他报错、得到的错误
let p = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject('这是失败结果')
  },3000)
})

// 一个普通的函数加上 async
async function fun(){
    let obj = {
    name:'zjf',
    age:18
  }
  console.log('我先不等了'); //第一时间就出来了
  let reson = await p

}
//执行函数
fun().catch((error)=>{
  console.log(error);  //这是失败结果
})

在async中是异步执行

let p = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    let obj = {
    name:'zjf',
    age:18
  }
    resolve('这是成功结果'+obj)
  },3000)
})

// 一个普通的函数加上 async
// 异步任务
async function fun(){
  console.log('我先不等了'); //第一时间就出来了
    setTimeout(()=>{
      console.log('我是5000秒执行'); //最后执行
  },5000)
  let reson = await p
  console.log(reson); //这是成功结果[object Object]
}
//执行函数
fun()
// 运行结果:
// 我先不等了
//  这是成功结果[object Object]
//  我是5000秒执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端达闻西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值