Promise学习笔记(二)

Promise学习笔记(二)

个人博客:Promise学习笔记(二)

1. 改变promise的状态

promise的状态一开始是pending,改变promise的状态有三个方法:

  • 调用resolve函数:pending => fulfilled(resolved)
  • 调用reject函数:pending => rejected
  • 抛出异常:pending => rejected
// 0. 初始状态:pending
const p0 = new Promise((resolve, reject) => {})
console.log(p0)

// 1. 调用resolve函数:pending => fulfilled(resolved)
const p1 = new Promise((resolve, reject) => {
  resolve('ok')
})
console.log(p1)

// 2. 调用reject函数:pending => rejected
const p2 = new Promise((resolve, reject) => {
  reject('error')
})
console.log(p2)
p2.catch(reason => {
  console.log(reason)
})

// 3. 抛出异常:pending => rejected
const p3 = new Promise((resolve, reject) => {
  throw '抛出异常'
})
console.log(p3)
p3.catch(reason => {
  console.log(reason)
})

image-20220226173041998

2. 指定多个回调

当promise改变为对应状态时都会调用

const p = Promise.resolve('ok')
p.then(value => {
  console.log('指定的第一个回调函数')
})

p.then(value => {
  console.log('指定的第二个回调函数')
  console.log('%c---------------', 'color: red; font-size: 24px')
})


const p1 = Promise.reject('error')
p1.then(value => {
  console.log('指定的第一个回调函数') // 失败的结果,不会调用这个成功时才调用的函数
})

p1.catch(reason => {
  console.log('指定的第二个回调函数')
})

image-20220226174300677

3. then方法返回结果

then()方法返回新的Promise对象

const p1 = Promise.resolve('ok')

// 1. 抛出异常
let result1 = p1.then(value => {
  throw '抛出异常'
}, reason => {
  console.warn(reason)
})
console.log(result1) // [[PromiseState]]: "rejected"

// 2. 非Promise类型的对象
const result2 = p1.then(value => {
  return 'Hello, CLZ!' // [[PromiseState]]: "fulfilled"
})
console.log(result2)

// 3. Promise类型的对象
// 3.1 结果成功
const result3 = p1.then(value => {
  return new Promise((resolve, reject) => {
    resolve('success')
  })
})
console.log(result3)

// 3.2 结果失败
const result4 = p1.then(value => {
  return new Promise((resolve, reject) => {
    reject('error')
  })
})
console.log(result4)

image-20220226203535240

4. 串联多个任务

链式调用原理:then()返回的是Promise对象

const p1 = Promise.resolve('ok')

p1.then(value => {
  return new Promise((resolve, reject) => {
    resolve('success')
  })
}).then(value => {
  console.log(value) // success
  return value
}).then(value => {
  console.log(value) // success
  return value
})

5. 异常穿透

  • 当使用Promise的then链式调用时,可以在最后指定失败的回调
  • 前面任何操作出异常都会传给最后失败的回调处理
const p1 = Promise.resolve('ok')

p1.then(value => {
  return new Promise((resolve, reject) => {
    resolve('success')
  })
}).then(value => {
  console.log(value)
  throw '出现异常'
  return value
}).then(value => {
  console.log(value)
  return value
}).catch(reason => {
  console.warn(reason)
})

6. 中断Promise链

有且只有一个方式:返回一个pending状态的Promise对象

因为返回一个pending状态的对象时,后续的回调就不能执行了,因为后面的回调函数只有在状态发生变化时才能执行。

const p1 = Promise.resolve('ok')

p1.then(value => {
  return new Promise((resolve, reject) => {
    resolve('success')
  })
}).then(value => {
  console.log(1)
}).then(value => {
  console.log(2)
  return new Promise(() => {}) // 只输出1, 2
  // return false    // 无效果
}).then(value => {
  console.log(3)
}).catch(reason => {
  console.warn(reason)
})

7. Promise自定义封装

7.1 基本结构的搭建

promise.js

function Promise(executor) {

}


Promise.prototype.then = function (onResolved, onRejected) {

}

测试用: index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>手写Promise</title>
  <script src="./promise.js"></script>
</head>

<body>
  <script>
    let p = new Promise((resolve, reject) => {
      resolve('OK')
    })

    p.then(value => {
      console.log(value)
    }, reason => {
      console.warn(reason)
    })
  </script>
</body>

</html>

7.2 resolve、reject功能实现

// resolve函数
const resolve = (data) => {
  // 1. 修改对象的状态(promiseState)
  this.PromiseState = 'fulfilled'

  // 2. 设置对象结果值(promiseResult)
  this.PromiseResult = data
}


// reject函数
const reject = (data) => {
  // 1. 修改对象的状态(promiseState)
  this.PromiseState = 'rejected'

  // 2. 设置对象结果值(promiseResult)
  this.PromiseResult = data
}

promise.js

function Promise(executor) {
  this.PromiseState = 'pending'
  this.PromiseResult = null

  // resolve函数
  const resolve = (data) => {
    // 1. 修改对象的状态(promiseState)
    this.PromiseState = 'fulfilled'

    // 2. 设置对象结果值(promiseResult)
    this.PromiseResult = data
  }

  // reject函数
  const reject = (data) => {
    // 1. 修改对象的状态(promiseState)
    this.PromiseState = 'rejected'

    // 2. 设置对象结果值(promiseResult)
    this.PromiseResult = data
  }

  // 同步调用执行器函数executor
  executor(resolve, reject)
}


Promise.prototype.then = function (onResolved, onRejected) {

}

7.3 实现抛出异常改变promise状态

// 实现抛出异常改变promise状态
try {
  // 同步调用执行器函数executor
  executor(resolve, reject)
} catch (e) {
  reject(e)
}

7.4 实现Promise状态只能修改一次

pending => fulfilled(resolved)pending => rejected

只需要在resolve函数和reject函数最开始加上判断,Promise的状态是不是pending就行,如果不是,直接return

if (this.PromiseState !== 'pending') {
  return
}

7.5 实现then方法

Promise.prototype.then = function (onResolved, onRejected) {
  if (this.PromiseState === 'fulfilled') {
    onResolved(this.PromiseResult)
  } else if (this.PromiseState === 'rejected') {
    onRejected(this.PromiseResult)
  }
}

7.6 实现异步任务的执行

当任务是异步任务时,则无法执行成功或失败的回调函数,因为执行then参数时,状态是pending。

let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('OK')
  }, 0)
})

实现方法:

  • 自定义Promise对象增加一个callback对象,用于存成功、失败的回调函数

    this.callback = {}
    
  • then函数增加状态为pending的判断,这时候只是把回调函数存放起来,等到实际调用resolvereject函数时才调用存起来的回调函数

    if (this.PromiseState === 'fulfilled') {
        onResolved(this.PromiseResult)
      } else if (this.PromiseState === 'rejected') {
        onRejected(this.PromiseResult)
      } else {
        // 保存回调函数
        this.callback = {
          onResolved,
          onRejected
        }
      }
    
  • 调用resolvereject函数时,判断是否需要调用存起来的回调函数

    if (this.callback.onResolved) {  // ` resolve`或` reject`函数最后
      this.callback.onResolved(data)		// reject函数对应修改为onRejected
    }
    

7.7 指定多个回调函数

let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('OK')
  }, 1000)
})

p.then(value => {
  console.log(value)
}, reason => {
  console.warn(reason)
})

p.then(value => {
  alert(value)
}, reason => {
  alert(reason)
})

**会发现,最后只会弹出OK,而不会在控制台输出。**只是因为前面保存的callback属性是对象,所以后面的会覆盖掉前面的,改进只需要把callback变为数组即可

this.callbacks = []
Promise.prototype.then = function (onResolved, onRejected) {
  if (this.PromiseState === 'fulfilled') {
    onResolved(this.PromiseResult)
  } else if (this.PromiseState === 'rejected') {
    onRejected(this.PromiseResult)
  } else {
    this.callbacks.push({
      onResolved,
      onRejected
    })
  }
}
this.callbacks.forEach(item => {		 // ` resolve`或` reject`函数最后
  item.onResolved(data)				// reject函数对应修改为onRejected
})

7.8 then方法返回结果

成功时的代码修改如下图,失败的类似

只实现同步

return new Promise((resolve, reject) => {
    if (this.PromiseState === 'fulfilled') {
      try {
        // 获取回调函数的执行结果
        const result = onResolved(this.PromiseResult)

        if (result instanceof Promise) {
          // 结果是Promise类型对象 
          result.then(v => {
            resolve(v)
          }, r => {
            reject(r)
          })
        } else {
          resolve(result)
        }

      } catch (e) {
        reject(e)
      }
    }
    // else if (this.PromiseState === 'rejected') {
    //   onRejected(this.PromiseResult)
    // } else {
    //   this.callbacks.push({
    //     onResolved,
    //     onRejected
    //   })
    // }
  })

实现异步

const self = this

this.callbacks.push({
  onResolved: function () {
    try {
      let result = onResolved(self.PromiseResult)
      if (result instanceof Promise) {
        result.then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      } else {
        resolve(result)
      }
    } catch (e) {
      reject(e)
    }
  },
  onRejected: function () {
    // 类似上面
  }
})

7.9 then方法封装优化

function callback(type) {
  try {
    // 获取回调函数的执行结果
    const result = type(self.PromiseResult)

    if (result instanceof Promise) {
      // 结果是Promise类型对象 
      result.then(v => {
        resolve(v)
      }, r => {
        reject(r)
      })
    } else {
      resolve(result)
    }

  } catch (e) {
    reject(e)
  }
}
Promise.prototype.then = function (onResolved, onRejected) {
  return new Promise((resolve, reject) => {
    const self = this

    function callback(type) {
      try {
        // 获取回调函数的执行结果
        const result = type(self.PromiseResult)

        if (result instanceof Promise) {
          // 结果是Promise类型对象 
          result.then(v => {
            resolve(v)
          }, r => {
            reject(r)
          })
        } else {
          resolve(result)
        }

      } catch (e) {
        reject(e)
      }
    }

    if (this.PromiseState === 'fulfilled') {
      callback(onResolved)
    }
    else if (this.PromiseState ===   'rejected') {
      callback(onRejected)
    } else {
      this.callbacks.push({
        onResolved: function () {
          callback(onResolved)
        },
        onRejected: function () {
          callback(onRejected)
        }
      })
    }
  })
}

7.10 catch方法

异常穿透:因为catch方法支持只传一个参数reason => {},而then方法第二个参数才是reason => {},所以会出问题:最后调用catch时没有onRejected方法

所以,需要在then方法开始的时候添加以下判断

if (typeof onRejected !== 'function') {
  onRejected = reason => {
    throw reason
  }
}

catch方法还应实现值传递,即then可以不传参数,那么和上面的原理一样,还需要添加当onResolved不存在的情况

if (typeof onResolved !== 'function') {
  onResolved = value => value
}

测试用:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>手写Promise</title>
  <script src="./promise.js"></script>
</head>

<body>
  <script>
    let p = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('ok')
      }, 1000)
    })

    p.then()
      .then(value => {
        console.log(222)
      }).then(value => {
        console.log(333)
      }).catch(reason => {
        console.warn(reason)
      })
  </script>
</body>

</html>

7.11 API

7.11.1 resolve方法和reject方法
// resolve方法
Promise.resolve = function (value) {
  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)
  })
}
7.11.2 all方法
// all方法
Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    let arr = []
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(v => {
        arr[i] = v
        if (arr.length === promises.length) {
          resolve(arr)
        }
      }, r => {
        reject(r)
      })
    }
  })
}

测试:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>手写Promise</title>
  <script src="./promise.js"></script>
</head>

<body>
  <script>
    const p1 = new Promise((resolve, reject) => {
      resolve('p1: OK')
    })
    const p2 = Promise.resolve('p2: OK')
    const p3 = Promise.resolve('p3: OK')
    const result1 = Promise.all([p1, p2, p3]) // 所有Promise的结果都成功
    console.log(result1)


    const p4 = Promise.resolve('p4: OK')
    const p5 = Promise.reject('p5: Err')
    const p6 = Promise.reject('p6: Err')
    const result2 = Promise.all([p4, p5, p6]) // 有Promise的结果失败
    console.log(result2)
  </script>
</body>

</html>

image-20220227171844700

7.11.3 race方法
// 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)
      })
    }
  })
}

7.12 then方法回调是异步执行

// 1 3 2:then方法异步执行,得等同步方法执行完才执行
const p1 = new Promise((resolve, reject) => {
  resolve('ok')
  console.log(1)
})

p1.then(value => {
  console.log(2)
})

console.log(3)

自定义Promise实现then方法回调异步执行:就是把原本调用成功、失败时的回调函数变为异步的就行了

if (this.PromiseState === 'fulfilled') {
  setTimeout(() => {
    callback(onResolved)
  })
}

image-20220227175150352

7.13. 完整代码

function Promise(executor) {
  this.PromiseState = 'pending'
  this.PromiseResult = null
  this.callbacks = []

  // resolve函数
  const resolve = (data) => {
    if (this.PromiseState !== 'pending') {
      return
    }

    // 1. 修改对象的状态(promiseState)
    this.PromiseState = 'fulfilled'

    // 2. 设置对象结果值(promiseResult)
    this.PromiseResult = data

    setTimeout(() => {
      this.callbacks.forEach(item => {
        item.onResolved(data)
      })
    })

  }

  // reject函数
  const reject = (data) => {
    if (this.PromiseState !== 'pending') {
      return
    }

    // 1. 修改对象的状态(promiseState)
    this.PromiseState = 'rejected'

    // 2. 设置对象结果值(promiseResult)
    this.PromiseResult = data

    setTimeout(() => {
      this.callbacks.forEach(item => {
        item.onRejected(data)
      })
    })

  }

  // 实现抛出异常改变promise状态
  try {
    // 同步调用执行器函数executor
    executor(resolve, reject)
  } catch (e) {
    reject(e)
  }
}

// then方法
Promise.prototype.then = function (onResolved, onRejected) {
  if (typeof onRejected !== 'function') {
    onRejected = reason => {
      throw reason
    }
  }

  if (typeof onResolved !== 'function') {
    onResolved = value => value
  }

  return new Promise((resolve, reject) => {
    const self = this

    function callback(type) {
      try {
        // 获取回调函数的执行结果
        const result = type(self.PromiseResult)

        if (result instanceof Promise) {
          // 结果是Promise类型对象 
          result.then(v => {
            resolve(v)
          }, r => {
            reject(r)
          })
        } else {
          resolve(result)
        }

      } catch (e) {
        reject(e)
      }
    }

    if (this.PromiseState === 'fulfilled') {
      setTimeout(() => {
        callback(onResolved)
      })
    }
    else if (this.PromiseState === 'rejected') {
      setTimeout(() => {
        callback(onRejected)
      })
    } else {
      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) {
  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) {
  return new Promise((resolve, reject) => {
    let arr = []
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(v => {
        arr[i] = v
        if (arr.length === 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)
      })
    }
  })
}

封装成类版本:

class Promise {
  constructor(executor) {
    this.PromiseState = 'pending'
    this.PromiseResult = null
    this.callbacks = []

    // resolve函数
    const resolve = (data) => {
      if (this.PromiseState !== 'pending') {
        return
      }

      // 1. 修改对象的状态(promiseState)
      this.PromiseState = 'fulfilled'

      // 2. 设置对象结果值(promiseResult)
      this.PromiseResult = data

      setTimeout(() => {
        this.callbacks.forEach(item => {
          item.onResolved(data)
        })
      })

    }

    // reject函数
    const reject = (data) => {
      if (this.PromiseState !== 'pending') {
        return
      }

      // 1. 修改对象的状态(promiseState)
      this.PromiseState = 'rejected'

      // 2. 设置对象结果值(promiseResult)
      this.PromiseResult = data

      setTimeout(() => {
        this.callbacks.forEach(item => {
          item.onRejected(data)
        })
      })

    }

    // 实现抛出异常改变promise状态
    try {
      // 同步调用执行器函数executor
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }

  then(onResolved, onRejected) {

    if (typeof onRejected !== 'function') {
      onRejected = reason => {
        throw reason
      }
    }

    if (typeof onResolved !== 'function') {
      onResolved = value => value
    }

    return new Promise((resolve, reject) => {
      const self = this

      function callback(type) {
        try {
          // 获取回调函数的执行结果
          const result = type(self.PromiseResult)

          if (result instanceof Promise) {
            // 结果是Promise类型对象 
            result.then(v => {
              resolve(v)
            }, r => {
              reject(r)
            })
          } else {
            resolve(result)
          }

        } catch (e) {
          reject(e)
        }
      }

      if (this.PromiseState === 'fulfilled') {
        setTimeout(() => {
          callback(onResolved)
        })
      }
      else if (this.PromiseState === 'rejected') {
        setTimeout(() => {
          callback(onRejected)
        })
      } else {
        this.callbacks.push({
          onResolved: function () {
            callback(onResolved)
          },
          onRejected: function () {
            callback(onRejected)
          }
        })
      }
    })

  }

  catch(onRejected) {
    return this.then(undefined, onRejected)
  }

  // resolve方法(静态方法,属于类而不是属于实例对象)
  static resolve(value) {
    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) {
    return new Promise((resolve, reject) => {
      let arr = []
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(v => {
          arr[i] = v
          if (arr.length === 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)
        })
      }
    })
  }
}


8. async和await

8.1 async函数

  • 函数的返回值是Promise对象
  • Promise对象的结果由async函数执行的返回值决定

和then方法一样

// 1. 返回值为一个非Promise类型的数据
async function test1() {
  return 123
}
let result1 = test1()
console.log(result1)

// 2. 返回值为一个Promise对象,结果为成功
async function test2() {
  return new Promise((resolve, reject) => {
    resolve('ok')
  })
}
let result2 = test2()
console.log(result2)

// 3. 返回值为一个Promise对象,结果为失败
async function test3() {
  return new Promise((resolve, reject) => {
    reject('error')
  })
}
let result3 = test3()
console.log(result3)

// 4. 抛出异常
async function test4() {
  throw '抛出异常'
}
let result4 = test4()
console.log(result4)

image-20220227192621644

8.2 await表达式

  • await右侧的表达式一般是Promise对象,但也可以是其他值
  • 如果右侧的表达式是promise对象,await返回的是promise成功的值
  • 如果右侧的表达式是其他值,await返回的就是该值

注意:

  • await必须写在async函数中,但async函数中不一定要await
  • 如果await的promise失败,则会抛出异常,所以需要通过try...catch捕捉处理
let test = async () => {
  // 1. await右侧为其他类型的情况
  let result = await 123
  console.log(result) // 123

  // 2. await右侧为Promise的情况
  // 2.1 成功
  result = await new Promise((resolve, reject) => {
    resolve('ok')
  })
  console.log(result) // ok

  // 2.2 失败
  try {
    result = await new Promise((resolve, reject) => {
      reject('error')
    })
    console.log(result) // ok
  } catch (e) {
    console.log(e)
  }
}

test()

8.3 async和await使用

8.3.1 读取文件

情景:读取resource文件夹下的数据(1.txt,2.txt,3.txt),分别是111、222、333。并把数据拼接后在控制台打印出来。

回调函数版本

const fs = require('fs')

fs.readFile('./resource/1.txt', (err, data1) => {
  if (err) {
    throw err
  }
  fs.readFile('./resource/2.txt', (err, data2) => {
    if (err) {
      throw err
    }
    fs.readFile('./resource/3.txt', (err, data3) => {
      console.log(data1 + data2 + data3)
    })
  })
})

image-20220227194850320

async+await版本

const fs = require('fs')
const { promisify } = require('util')

const readFile = promisify(fs.readFile)

async function myReadFile() {
  try {
    let data1 = await readFile('./resource/1.txt')
    let data2 = await readFile('./resource/2.txt')
    let data3 = await readFile('./resource/3.txt')

    console.log(data1 + data2 + data3)
  } catch (e) {
    console.log(e)
  }
}

myReadFile()
8.3.2 axios使用

安装:npm install axios

(async function () {
  const axios = require('axios')

  const { data } = await axios.get('https://qcgx2i.api.cloudendpoint.cn/hello')
  console.log(data)
}())

image-20220227195827006

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值