Promise学习笔记

本文深入探讨了Promise的原理和使用,包括同步与异步回调的区别、Promise的状态变化、链式调用解决回调地狱的问题,以及自定义Promise的实现。同时讲解了async/await的使用和异步执行中的宏队列与微队列概念,还提供了相关的面试题以巩固理解。
摘要由CSDN通过智能技术生成

第1章 准备

1.1 区别实例对象与函数对象

  1. 实例对象:new 函数产生的对象,称为实例对象,简称为对象
  2. 函数对象:将函数作为对象使用,简称函数对象
function Fn() {
    // Fn 函数
}
const fn = new Fn() // Fn 是构造函数 fn是实例对象(对象)
console.log(Fn.prototype) // Fn 是函数对象
Fn.bind({
   }) // Fn 是函数对象
$('#test') // $ 是函数
$.get('/test') // $ 是函数对象

1.2 二种类型的回调函数

1.2.1 同步回调

  1. 理解:立即执行,完全执行完了才结束,不会放入会掉队列中
  2. 例子:数组遍历相关的回调函数 / Promiseexcutor 函数

1.2.2 异步回调

  1. 理解:不会立即执行,会放入回调队列中将来执行
  2. 例子:定时器回调 / ajax 回调 / Promise 的成功|失败的回调
// 1. 同步回调函数
const arr = [1, 3, 5]
arr.forEach(item => {
    // 遍历回调,每取出一个元素调用一次  同步回调函数,不会放到队列,一上来就要执行完
  console.log(item)
})
console.log('forEach()之后')
/*控制台打印信息:
    1
    3
    5
    forEach()之后
*/
// 2. 异步回调函数
setTimeout(()=>{
    // 异步回调函数,会放到队列中将来执行
  console.log("timeout callback()")
}, 0)
console.log("setTimeout之后")
/*控制台打印信息:
    setTimeout之后
    timeout callback()
*/

1.3 JS 的 error 处理

  • 目标:进一步理解JS中的错误(Error)和错误处理
    • mdn文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Error
  1. 错误的类型
    • Error:所有错误的父类型
    • ReferenceError:引用的变量不存在
      console.log(a) // Uncaught ReferenceError: a is not defined
      
    • TypeError:数据类型不正确的错误
      let b = null
      console.log(b.xxx) // Uncaught TypeError: Cannot read property 'xxx' of null
      
    • RangeError:数据值不在其允许的范围内
        function fn() {
             
          fn()
        }
        fn() // Uncaught RangeError: Maximum call stack size exceeded
      
    • SyntaxError:语法错误
      const c = """" // Uncaught SyntaxError: Unexpected string
      
  2. 错误处理
    • 捕获错误: try .. catch
      try {
             
        let d
        console.log(d.xxx)
      } catch (err) {
             
        console.log(err) // TypeError: Cannot read property 'xxx' of undefined
        // console.log(err.message)
        // console.log(err.stack)
      }
      console.log("出错之后")
      /*
        TypeError: Cannot read property 'xxx' of undefined
          at 03_准备_error.html?_ijt=k9vcnjofj3tsmvai7hl2lctrk5:47
        出错之后
       */
      
    • 抛出错误: throw error
      function someThing() {
             
        if (Date.now() % 2 === 1) {
             
          console.log("当前时间为奇数,可以执行任务")
        } else {
              // 如果时间为偶数,由调用者处理
          throw new Error("当前时间为偶数,无法执行任务")
        }
      }
      try {
             
        someThing()
      } catch (error) {
             
        alert(error.message)
      }
      
  3. 错误对象
    • message属性:错误相关信息
    • stack属性:函数调用栈记录信息

第2章 promise 的理解和使用

2.1 Promise 是什么?

2.1.1 理解

  1. 抽象表达:
    • Promise 是异步编程的新的解决方案(旧的是谁?)
  2. 具体表达:
    • 从语法上来说: Promise 是一个构造函数
    • 从功能上来说: Promise 对象用来封装一个异步操作并可以获取其结果

2.1.2 promise 的状态改变

  1. pending 变为 resolved
  2. pending 变为 rejected
  • 说明:只有这2种,切一个 promise 对象只能改变一次
    • 无论是成功还是失败,都会有一个结果数据
    • 成功的结果数据一般称为 value,失败的结果数据一般称为 reason

2.1.3 promise 的基本流程

promise的基本流程

2.1.4 promise 的基本使用

// 1. 创建一个新的 promise
const p = new Promise((resolve, reject) => {
    // 执行器函数
  // 2. 执行异步操作任务
  setTimeout(()=> {
   
    const time = Date.now() // 如果当前时间是偶数就代表成功,否则代表失败
    if(time % 2 === 0) {
    // 3.1 如果成功了,调用 resolve(value)
      resolve("成功的数据,time=" + time)
    } else {
    // 3.2 如果失败了,调用 reject(reason)
      reject("失败的数据,time=" + time)
    }
  })
}).then(value => {
    // 接收得到成功的 value 数据  onResolved
  console.log("成功的回调 ", value)
}, reason => {
    // 接收得到的失败的 reason 数据  onRejected
  console.log("失败的回调 ", reason)
})
/*
    成功的回调  成功的数据,time=1604644474094
    或
    失败的回调  失败的数据,time=1604644507259
*/

2.2 为什么要用 Promise?

2.2.1 指定回调函数的方式更加灵活

  1. 旧的:必须在启动异步任务前指定(先指定回调函数,再启动异步任务)
  2. promise:启动异步任务 => 返回 promise 对象 => 给 promise 对象绑定回调函数(甚至可以在异步任务结束后指定/多个)

2.2.2 支持链式调用,可以解决回调地狱问题

  1. 什么是回调地狱?
    • 回调函数嵌套调用,外部回调函数异步执行的结果是其内部嵌套的回调函数执行的条件
    doSomething(function(result) {
         
      doSomethingElse(result, function(newResult) {
         
        doThirdThing(newResult, function(finalResult) {
         
          console.log('Got the final result:' + finalResult)
        }, failureCallback)
      }, failureCallback)
    }, failureCallback)
    
  2. 回调地狱的缺点?
    • 不便于阅读
    • 不便于异常处理
  3. 解决方案
    • promise 链式调用
    doSomething()
      .then(result => doSomethingElse(result))
      .then(newResult => doThirdThing(newResult))
      .then(finalResult => {
         
         console.log('Got the final result:' + finalResult)
      })
      .catch(failureCallback)
    
  4. 终极解决方案
    • async / await
    async function request() {
         
      try{
         
        const result = await doSomething()
        const newResult = await doSomethingElse(result)
        const finalResult = await doThirdThing(newResult)
        console.log('Got the final result:' + finalResult)
      } catch (error) {
         
        failureCallback(error)
      }
    }
    

2.3 如何使用 Promise?

2.3.1 API

  1. Promise 构造函数: Promise(excutor) {}
    • excutor 函数:同步执行 (resolve, reject) => {}
    • resolve 函数:内部定义成功时我们调用的函数 value => {}
    • reject 函数:内部定义失败时我们调用的函数 reason => {}
    • 说明:excutor 会在 Promise 内部立即同步回调,异步操作在执行器中执行
  2. Promise.prototype.then 方法: (onResolved, onRejected) => {}
    • onResolved 函数:成功的回调函数 value => {}
    • onRejected 函数:失败的回调函数 reason => {}
    • 说明:指定用于得到成功 value 的成功回调和用于得到失败 reason 失败回调,返回一个新的 Promise 对象
  3. Promise.prototype.catch 方法: p.catch(onRejected)
    • onRejected 函数:失败的回调函数 reason => {}
    • 说明:then() 的语法糖,相当于 then(undefined, onRejected)
new Promise((resolve, reject)=>{
   
  setTimeout(()=>{
   
    resolve("成功的数据")
    // reject("失败的数据")
  }, 1000)
}).then(
    value => {
   
      console.log("onResolved()1", value)
    }
).catch(
    reason => {
   
      console.log("onRejected()1", reason)
    }
)
  1. Promise.resolve 方法:value => {}
    • value: 成功的数据或promise对象
    • 说明:返回一个成功/失败的 promise 对象
  2. Promise.reject 方法:reason => {}
    • reason: 失败的原因
    • 说明:返回一个失败的 promise 对象
// 产生一个成功值为1 的promise对象
const p1 = new Promise((resolve, reject)=>{
   
  resolve(1)
})
const p2 = Promise.resolve(2) // 语法糖
const p3 = Promise.reject(3)
p1.then(value => {
    console.log(value) })
p2.then(value => {
    console.log(value) })
p3.then(null, reason => {
    console.log(reason) })
p3.catch(reason => {
    console.log(reason) })
  1. Promise.all 方法:promises => {}
    • promises:包含n个 promise 的数组
    • 说明:返回一个新的 promise,只有所有的 promise 都成功才成功,只要有一个失败了就直接失败
  2. Promise.race 方法: promises => {}
    • promises:包含n个 promise 的数组
    • 说明:返回一个新的 promise,第一个完成的 promise 的结果状态就是最终的结果状态
// 产生一个成功值为1 的promise对象
const p1 = new Promise((resolve, reject)=>{
   
  resolve(1)
})
const p1_1 = new Promise((resolve, reject)=>{
   
  setTimeout(()=>{
   
    resolve(1)
  }, 100)
})
const p2 = Promise.resolve(2) // 语法糖
const p3 = Promise.reject(3)
p1.then(value => {
    console.log(value) })
p2.then(value => {
    console.log(value) })
p3.then(null, reason => {
    console.log(reason) })
p3.catch(reason => {
    console.log(reason) })

const pAll = Promise.all([p1, p2, p3])
pAll.then(
  value => {
    console.log("all onResolved()", value) },
  reason => {
    console.log("all onRejected()", reason) } //all onRejected() 3
)
const pAll2 = Promise.all([p1, p2])
pAll2.then(
    values => {
    console.log("all onResolved()", values) }, // all onResloved() [1, 2]
    reason => {
    console.log("all onRejected()", reason) }
)

const pRace = Promise.race([p1, p2, p3])
pRace.then(
    value => {
    console.log("all onResolved()", value) }, // all onResolved() 1
    reason => {
    console.log("all onRejected()", reason) }
)
const pRace1 = Promise.race([p1_1, p2, p3])
pRace1.then(
    value => {
    console.log("all onResolved()", value) }, // all onResolved() 2
    reason => {
    console.log("all onRejected()", reason) }
)
const pRace2 = Promise.race([p3, p1, p2])
pRace2.then(
    value => {
    console.log("all onResolved()", value) },
    reason => {
    console.log("all onRejected()", reason) } // all onRejected() 3
)

2.3.2 promise的几个关键问题

  1. 如何改变 promise 状态?
    • resolve(value):如果当前是 pending 就会变成 resolved
    • rejected(reason):如果当前是 pending 就会变成 rejected
    • 抛出异常:如果当前是 pending 就会变成 rejected
    const p = new Promise((resolve, reject) => {
         
      // resolve(1) // promise 变为 resolved 成功状态
      // reject(2) // promise 变为 rejected 成功状态
      throw new Error("出错了") // 抛出异常,promise 变为 rejected 成功状态,reason为抛出的error
    })
    p.then(
      value => {
         
        console.log("value", value)
      },
      reason => {
         
        console.log("reason", reason)
        /*
          reason Error: 出错了
            at 04_promise的几个关键问题.html?_ijt=sumrlanirspdi97b31m1rurrfl:21
            at new Promise (<anonymous>)
            at 04_promise的几个关键问题.html?_ijt=sumrlanirspdi97b31m1rurrfl:18
         */
      }
    )
    
  2. 一个 promise 指定多个成功/失败回调函数,都会调用吗?
    • promise 改变为对应状态时都会调用
    const p = new Promise((resolve, reject) => {
         
      // resolve(1) // promise 变为 resolved 成功状态
      // reject(2) // promise 变为 rejected 成功状态
      throw new Error("出错了") // 抛出异常,promise 变为 rejected 成功状态,reason为抛出的error
    })
    p.then(
      value => {
         
        console.log("value", value)
      },
      reason => {
         
        console.log("reason", reason)
      }
    )
    p.then(
        value => {
         
          console.log("value", value)
        },
        reason => {
         
          console.log("reason2", reason)
        }
    )
      /*
          reason Error: 出错了
            at 04_promise的几个关键问题.html?_ijt=sumrlanirspdi97b31m1rurrfl:21
            at new Promise (<anonymous>)
            at 04_promise的几个关键问题.html?_ijt=sumrlanirspdi97b31m1rurrfl:18
              04_promise的几个关键问题
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值