Promise学习笔记(一)

Promise学习笔记(一)

一直有在用Promise,但是没有系统学过Promise,自然也不知道原理。现在就来学习一波。

1. 介绍

Promise是JS中进行异步编程的新解决方案。在这之前使用过回调函数进行异步编程。

Promise是一个构造函数,Promise对象用来封装一个异步操作并可以获取其成功或失败的结果值

Promise优点

  1. 支持链式调用,可解决回调地狱问题

回调地狱:回调函数嵌套使用

Promise学习笔记(一)
image-20220225162417514

回调地狱导致的问题

  • 阅读困难(后期维护麻烦)

  • 不便于异常处理

  1. 指定回调函数的方式更灵活
    • Promise:启动异步任务 => 返回Promise对象 => Promise对象绑定回调函数
    • 纯用回调函数:必须在启动异步任务前指定

2. Promise 体验

2.1 抽奖

先来一个抽奖示例(隔1s后出结果)

2.1.1 回调函数版本

<!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>
  </head>
  <body>
    <button class="btn" id="btn">抽奖</button>

    <script>
      function rand({
        return Math.floor(Math.random() * 100 + 1// 返回1到100之前的随机数
      }

      const btn = document.querySelector("#btn")

      btn.addEventListener("click"function ({
        setTimeout(() => {
          let n = rand()

          if (n <= 50) {
            alert("恭喜你中奖了")
          } else {
            alert("很遗憾,你没有中奖")
          }
        }, 1000)
      })
    
</script>
  </body>
</html>

Promise学习笔记(一)
promise

2.1.2 Promise版本

<!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>
</head>

<body>
  <button class="btn" id="btn">抽奖</button>

  <script>
    function rand({
      return Math.floor(Math.random() * 100 + 1// 返回1到100之前的随机数
    }

    const btn = document.querySelector("#btn")

    btn.addEventListener("click"function ({
      const p = new Promise((resolve, reject) => {
        // resolve 成功后执行的函数
        // reject 失败后执行的函数

        let n = rand()

        setTimeout(() => {
          if (n <= 50) {
            resolve(n) // 可以将Promise的状态设置为成功
          } else {
            reject(n) // 可以将Promise的状态设置为失败
          }
        }, 1000)
      })

      p.then(
        // 通过then方法指定成功或失败时的回调函数,第一个参数是成功时的回调,第二个参数是失败时的回调
        (value) => {
          alert(`恭喜你,中奖了,中奖号码是${value}`)
        },
        (value) => {
          alert(`真遗憾,你没有中奖,中奖号码是${value}`)
        }
      )
    })
  
</script>
</body>

</html>

2.2 文件读取

2.2.1 回调函数版本

const fs = require('fs')

fs.readFile('./resource/content.txt', (err, data) => {
  if (err) {
    throw err
  }

  console.log(data.toString())
})

2.2.2 Promise版本

const fs = require('fs')

let p = new Promise((resolve, reject) => {
  fs.readFile('./resource/content1.txt', (err, data) => {
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

p.then((value) => {
  console.log(value.toString())
}, (reason) => {
  console.log(reason)
})
Promise学习笔记(一)
image-20220225172452214

2.3  AJAX

2.3.1 原生版本(回调函数)

<!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封装AJAX</title>
</head>

<body>
  <script>
    (function ({
      // 1. 创建对象
      const xhr = new XMLHttpRequest()

      // 2. 初始化
      xhr.open('GET''https://qcgx2i.api.cloudendpoint.cn/hello'// 接口可能会无效,换一个有效的就行

      // 3. 发送
      xhr.send()

      // 4. 处理响应结果
      xhr.onreadystatechange = function ({
        if (xhr.readyState === 4) {
          if (xhr.status >= 200 && xhr.status < 300) {
            console.log(xhr.response)
          } else {
            console.log(xhr.status)
          }
        }
      }
    })()
  
</script>
</body>

</html>
Promise学习笔记(一)
image-20220225174738518

2.3.2 Promise版本

<!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封装AJAX</title>
</head>

<body>
  <script>
    (function ({
      const p = new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();

        xhr.open('GET''https://qcgx2i.api.cloudendpoint.cn/hello');

        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((data) => {
        console.log(data)
      }, (statusCode) => {
        console.warn(statusCode)
      })
    })()
  
</script>
</body>

</html>

3. 转化为Promise风格(promisify)

**util.promisify()**:传入一个遵循常见的错误优先的回调风格的函数(即以 (err, value) => {...}作为最后一个参数),并返回Promise版本。

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

let pReadfile = promisify(fs.readFile)  // 把callback形式的异步api转化成promise形式的

pReadfile('./resource/content.txt')
  .then(value => {
    console.log(value.toString())
  })

4. Promise属性

4.1 Promise状态

实例对象中的一个属性 [[PromiseState]],有三个值

  • pending:未决定
  • resolved(fulfilled):成功
  • rejected:失败

Promise的状态改变只有两种可能,且只能改变一次

  • pending变为resolved
  • pending变为rejected

成功的结果数据一般称为 value,失败的结果一般称为 reason

4.2. Promise对象的值

实例对象中的一个属性 [[PromiseResult]],保存着异步任务成功或失败的结果

只能通过resolve()reject() PromiseResult进行修改

const fs = require('fs')

let p = new Promise((resolve, reject) => {
  fs.readFile('./resource/content1.txt', (err, data) => {
    if (err) {
      reject(err)   // 通过reject()设置PromiseResult的值
    } else {
      resolve(data)
    }
  })
})

p.then((value) => {   // 把PromiseResult的值取出来,进行相关操作
  console.log(value.toString())
}, (reason) => {
  console.log(reason)
})

5. Promise工作流程

Promise学习笔记(一)
image-20220226145957472

6. Promise API

6.1 构造函数 Promise(excutor)

excutor函数:执行器, (resolve, reject) => {}

resolve函数:内部定义成功后调用的函数

reject函数:内部定义失败后调用的函数

构造函数会在Promise立即同步调用,异步操作在执行器中执行

let p = new Promise((resolve, reject) => {
  console.log(1)
})


console.log(2)

// 先输出1,再输出2

6.2 Promise.prototype.then方法

语法: promise.then(onResolved, onRejected)

onResolved函数:成功的回调函数, value => {}

onRejected函数:失败的回调函数, reason => {}

返回新的Promise对象

6.3 Promise.prototype.catch方法

与上面的then()类似,不过只能指定失败的回调函数

6.4 Promise.resolve方法

作用:接受一个参数,返回一个成功或失败的Promise对象。能够快速封装一个值,将这个值转化为Promise对象

  • 如果传入的参数是非Promise类型的对象,如字符串、数字等,则返回的结果是成功的Promise对象

  • 如果传入的参数是Promise对象,则参数的结果决定resolve的结果,即参数是成功的Promise对象的话,resolve的结果是成功的,反之是失败的

const p1 = Promise.resolve(123// Promise { 123 }

console.log(p1)


const p2 = Promise.resolve(p1) // 参数为成功的Promise对象

console.log(p2)

const p3 = Promise.resolve(new Promise((resolve, reject) => { // 参数为失败的Promise对象
  reject('Error')
}))

p3.catch(reason => {
  console.log(reason)
})

6.5 Promise.reject方法

接受一个参数,返回一个失败的Promise对象

const p1 = Promise.reject(123)
console.log(p1)

const p2 = Promise.reject(new Promise((resolve, reject) => {
  resolve('传参为成功的Promise对象')
}))

console.log(p2)
Promise学习笔记(一)
image-20220226153204273

6.5 Promise.all方法

参数:promises,promise的数组

返回一个新的Promise,当所有的promise都成功才成功,且结果为成功的结果组成的数组;有一个失败就直接失败,返回的结果就是失败的那一个的结果

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


const p3 = Promise.resolve('p3: OK')
const p4 = Promise.reject('p4: Err')
const p5 = Promise.reject('p5: Err')
const result2 = Promise.all([p3, p4, p5]) // 有Promise的结果失败
console.log(result2)
Promise学习笔记(一)
image-20220226170629148

如果想要捕捉异常,直接链式调用即可

const p3 = Promise.resolve('p3: OK')
const p4 = Promise.reject('p4: Err')
const p5 = Promise.reject('p5: Err')
const result2 = Promise.all([p3, p4, p5])
console.log(result2)

result2.catch(reason => {
  console.log(reason)
})
Promise学习笔记(一)
image-20220226170913348

6.6 Promise.race方法

参数:promises,promise的数组

返回一个新的Promise,第一个完成的结果是成功则成功,反之则失败

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p1: OK')
  })
})
const p2 = Promise.reject('p2: Err')
const result1 = Promise.race([p1, p2])
console.log(result1) // [[PromiseResult]]: "p2: Err"

result1.catch(reason => {
  console.log(reason)
})


原文始发于微信公众号(赤蓝紫):Promise学习笔记(一)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/45553.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!