Promise(简介、基本使用、API、手写实现 Promise、async与await)(一)

简介: Promise(简介、基本使用、API、手写实现 Promise、async与await)

前言

笔记根据视频与PPT进行整理

【视频链接:尚硅谷Web前端Promise教程从入门到精通】

【视频资源链接–阿里云盘】

【个人代码笔记–阿里云盘】

【视频资源个人代码笔记链接–百度网盘链接】

提取码:1234

字数4.5w+


1. Promise 简介

Promise 是一门新的技术(ES6 规范)

Promise 是 JS 中进行异步编程的新解决方案。(旧方案是单纯使用回调函数)

异步编程:

  • fs 文件操作
  • 数据库操作
  • AJAX
  • 定时器

旧方案中单纯使用回调函数,很可能会出现回调地狱回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件)的问题,不便于阅读,可读性差,不便于异常处理。

回调地狱:

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

2. Promise 基本使用

从语法上来说: Promise 是一个构造函数。

从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值。

2.1 Promise 基本使用体验

实现一个小功能:

点击按钮后显示是否中奖(30%概率中奖),若中奖弹出 “恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券” ,若未中奖弹出 “再接再厉”。

回调函数实现:

<!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>Document</title>
</head>
<body>
  <div class="container">
    <h2 class="page-header">Promise 初体验</h2>
    <button class="btn btn-primary" id="btn">点击抽奖</button>
  </div>
  <!-- 不使用Promise,使用回调函数实现 -->
  <script>
    //生成随机数
    function rand(m,n){
      return Math.ceil(Math.random() * (n-m+1)) + m-1;
    }
    /**
    点击按钮后显示是否中奖(30%概率中奖)
      若中奖弹出   恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
      若未中奖弹出 再接再厉
    */
    //获取元素对象
    const btn = document.querySelector('#btn');
    //绑定单击事件
    btn.addEventListener('click', function(){
      // 定时器
      setTimeout(() => {
          //30%  1-100 取出一个数字,小于等于30==中奖
          //获取从1 - 100的一个随机数
          let n = rand(1, 100);
          //判断
          if(n <= 30){
              alert('恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券');
          }else{
              alert('再接再厉');
          }
      }, 0);
    })
  </script>
</body>
</html>

基于 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>Document</title>
</head>
<body>
  <div class="container">
    <h2 class="page-header">Promise 初体验</h2>
    <button class="btn btn-primary" id="btn">点击抽奖</button>
  </div>
  <!-- 使用Promise实现 -->
  <script>
    //生成随机数
    function rand(m,n){
      return Math.ceil(Math.random() * (n-m+1)) + m-1;
    }
    /**
    点击按钮后显示是否中奖(30%概率中奖)
      若中奖弹出   恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
      若未中奖弹出 再接再厉
    */
    //获取元素对象
    const btn = document.querySelector('#btn');
    //绑定单击事件
    btn.addEventListener('click', function(){
      //Promise 形式实现
      // Promise 构造函数接收的参数为一个函数(函数的参数为两个函数)
      // resolve 解决  函数类型的数据
      // reject  拒绝  函数类型的数据
      // 1) 创建 promise 对象(pending 状态), 指定执行器函数
      const p = new Promise((resolve, reject)=>{
        // 2) 在执行器函数中启动异步任务
        setTimeout(() => {
            let n = rand(1, 100);
            //判断
            // 3) 根据结果做不同处理
            if(n <= 30){
              // 如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状态
              resolve(n); // 将 promise 对象的状态设置为 『成功』调用 resolve 函数
            }else{
              // 如果失败了, 调用 reject(), 指定失败的 reason, 变为 rejected 状态
              reject(n); // 将 promise 对象的状态设置为 『失败』调用 reject 函数
            }
        }, 0);
      })
      //调用 then 方法
      // 指定成功和失败要执行的函数
      // 状态为成功,调用第一个函数,状态为失败,执行第二个函数
    // 成功失败函数的参数
      // value 值 成功函数参数
      // reason 理由 失败函数参数
      p.then((value) => {
          alert('恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券, 您的中奖数字为 ' + value);
      }, (reason) => {
          alert('再接再厉, 您的号码为 ' + reason);
      });
    })
  </script>
</body>
</html>

2.2 基于 promise 的形式读取文件

回调函数形式实现:

// 导入 fs 模块
const fs = require('fs');
// 回调函数的方式读取文件
fs.readFile( './content.txt', (err, data)=>{
  if ( err ) throw err // 出错抛出错误
  console.log( data.toString() ) //输出内容
} )

基于 Promise 实现:

// 导入 fs 模块
const fs = require('fs')
// 基于promise读取文件
const p = new Promise( (resolve, reject)=>{
  fs.readFile( './content.txt', (err, data)=>{
    if ( err ) reject( err )
    else resolve( data )
  } )
} )
// 调用then处理读取文件的结果
p.then( value=>{
  console.log( value.toString() )
}, reason=>{
  console.log(reason)
} )

2.3 基于 Promise 的 ajax 请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise 封装 AJAX</title>
</head>
<body>
  <div class="container">
    <h2 class="page-header">Promise 封装 AJAX 操作</h2>
    <button class="btn btn-primary" id="btn">点击发送 AJAX</button>
  </div>
  <script>
    // 接口地址 https://api.liulongbin  跨域了
    // https://www.escook.cn/api/get  跨域了
    // 获取按钮
    const btn = document.querySelector('#btn')
    btn.addEventListener( 'click', ()=>{
      // 创建 Promise 对象
      const p = new Promise( (resolve, reject)=>{
        // 创建请求对象
        const xhr = new XMLHttpRequest()
        // 初始化
        xhr.open( 'GET', 'https://www.escook.cn/api/get' ) // 跨域了
        // 设置请求头
        // xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        // 发送请求
        xhr.send()
        // 处理响应的结果
        xhr.onreadystatechange = ()=>{
          if ( xhr.readyState===4 ) {
            // 成功
            if ( xhr.status>=200 && xhr.status<300 ) {
              // 请求响应信息 xhr.response
              resolve( xhr.response )
            } else {
              // xhr.status 请求状态
              reject( xhr.status )
            }
          }
        }
      } )
      p.then( value=>{
        console.log( value )
      }, reason=>{
        console.log( reason )
      } )
    } )
  </script>
</body

请求失败,调用失败的处理函数,打印请求状态码

2.4 基于 Promise 封装 fs 模块读取文件

/**
 * 封装一个函数 mineReadFile 读取文件内容
 * 参数:  path  文件路径
 * 返回:  promise 对象
 */
// 导入 fs
const fs = require( 'fs' )
const mineReadFile = ( path )=>{
  return new Promise( (resolve, reject)=>{
    fs.readFile( path, ( err, data )=>{
      if(err) reject(err)
      resolve(data)
    } )
  } )
}
// 调用读取文件的方法
// 指定对应的成功和失败的处理函数
mineReadFile( './content.txt' )
.then( val=>{
  // 输出文件的内容
  console.log( val.toString() )
}, reason=>{
  // 输出错误信息
  console.log( reason )
} )

2.5 util.promisify 方法封装转化成 Promise

/**
 * util.promisify 方法
 */
// 引入 util 模块
const util = require( 'util' )
// 引入 fs 模块
const fs = require( 'fs' )
// 使用 util.promisify 方法封装 fs.readFile 
// 参数为一个函数
const mineReadFile = util.promisify( fs.readFile )
// 调用函数,并且指定对应的成功和失败处理函数
mineReadFile( './content.txt' ).then( val=>{
  console.log( val.toString() )
}, reason=>{
  console.log( reason )
} )

2.6 Promise封装AJAX操作

<!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>Document</title>
</head>
<body>
  <script>
    /**
     * 封装一个函数 sendAJAX 发送 GET AJAX 请求
     * 参数   URL
     * 返回结果 Promise 对象
     */
    function sendAJAX( url ) {
      return new Promise( (resolve, reject)=>{
        const xhr = new XMLHttpRequest()
        xhr.responseType = 'json'
        xhr.open("GET", url)
        xhr.send();
        //处理结果
        xhr.onreadystatechange = function(){
          if(xhr.readyState === 4){
            //判断成功
            if(xhr.status >= 200 && xhr.status < 300){
              //成功的结果
              resolve(xhr.response);
            }else{
              reject(xhr.status);
            }
          }
        }
      } )
    }
    // 调用指定处理函数
    sendAJAX('https://api.apiopen.top/getJok')
    .then(value => {
      console.log(value);
    }, reason => {
      console.warn(reason);
    });
  </script>
</body>
</html>

依旧跨域问题,请求失败,调用失败的处理函数,打印请求状态码

2.7 promise 的状态

实例对象中的一个属性 『PromiseState』

  • pending 未决定的
  • resolved / fullfilled 成功
  • rejected 失败

promise 的状态改变

  1. 成功 pending 变为 resolved / fullfilled
  2. 失败 pending 变为 rejected

说明:

只有这 2 种(只能pending 变为 resolved / fullfilled 或 pending 变为 rejected,没有其他的状态变化), 且一个 promise 对象只能改变一次,无论变为成功还是失败, 都会有一个结果数据,成功的结果数据一般称为 value, 失败的结果数据一般称为 reason。

2.8 promise 的基本流程

promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个) => 根据函数中执行成功或失败的结果,改变promise的状态 => 调用对应的成功或失败的函数。

3. Promise API

3.1 Promise 构造函数

Promise (excutor)
  • (1) executor 函数: 执行器 (resolve, reject) => {}
  • (2) resolve 函数: 内部定义成功时我们调用的函数 value => {}
  • (3) reject 函数: 内部定义失败时我们调用的函数 reason => {}

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

// 成功
    // 创建Promise实例对象时同步执行传入的执行器函数
    const p1 = new Promise( (resolve, reject)=>{
      console.log( 'executor 执行' )
      if(true) {
        resolve()
      } else {
        reject()
      }
    } )
    console.log( p1 )
    // 失败
    const p2 = new Promise( (resolve, reject)=>{
      console.log( 'executor 执行' )
      if(false) {
        resolve()
      } else {
        reject()
      }
    } )
    console.log( p2 )

3.2 Promise.prototype.then 方法

Promise.prototype.then 方法: (onResolved, onRejected) => {}
  • (1) onResolved 函数: 成功的回调函数 (value) => {}
  • (2) onRejected 函数: 失败的回调函数 (reason) => {}

指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调返回一个新的 promise 对象

// 成功
    const p1 = new Promise( (resolve, reject)=>{
      resolve('ok')
    } )
    // 执行第一个函数 -- 成功的回调函数
    p1.then( val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    } )
    // 失败
    const p2 = new Promise( (resolve, reject)=>{
      reject('Error')
    } )
    // 执行第二个函数 -- 失败的回调函数
    p2.then( val=>{
      console.log(val)
    }, reason=>{
      console.log(reason)
    } )

3.3 Promise.prototype.catch 方法

Promise.prototype.catch 方法: (onRejected) => {}
  • onRejected 函数: 失败的回调函数 (reason) => {}

then()的语法糖, 相当于: then(undefined, onRejected)

catch 定义用于处理失败的回调函数,不定义成功的回调函数

const p = new Promise( (resolve, reject)=>{
      reject('error')
    } )
    // Promise的状态为失败时才调用catch中的回调函数
    p.catch( reason=>{
      console.log(reason)
    } )
    const pp = new Promise( (resolve, reject)=>{
      resolve('ok')
    } )
    // Promise的状态为失败时才调用catch中的回调函数
    pp.catch( reason=>{
      console.log(reason)
    } )


相关文章
|
1天前
|
前端开发 JavaScript
JavaScript 中的异步编程:Promise 和 Async/Await 的实现与应用
在Web开发中,JavaScript异步编程是一个不可忽视的重要话题。本文将深入探讨JavaScript中Promise和Async/Await的实现原理与应用场景,通过实例代码带您了解如何优雅地处理异步操作,提升代码的可读性和可维护性。
|
18天前
|
前端开发 JavaScript
处理异步请求的 async/await 和 promise
处理异步请求的 async/await 和 promise
|
1月前
|
前端开发 C++
C++11实用技术(三)std::future、std::promise、std::packaged_task、async
C++11实用技术(三)std::future、std::promise、std::packaged_task、async
15 0
|
1月前
|
JavaScript 前端开发 IDE
Vue3【为什么选择Vue框架、Vue简介 、Vue API 风格 、Vue开发前的准备 、Vue项目目录结构 、模板语法、属性绑定 、 】(一)-全面详解(学习总结---从入门到深化)
Vue3【为什么选择Vue框架、Vue简介 、Vue API 风格 、Vue开发前的准备 、Vue项目目录结构 、模板语法、属性绑定 、 】(一)-全面详解(学习总结---从入门到深化)
36 1
|
1月前
|
前端开发 JavaScript
【面试题】async/await、promise和setTimeout的执行顺序
【面试题】async/await、promise和setTimeout的执行顺序
|
1月前
|
前端开发 JavaScript 开发者
【面试题】前端人70%以上 不了解的promise/async await
【面试题】前端人70%以上 不了解的promise/async await
|
1月前
|
Web App开发 前端开发 测试技术
【Web API系列】使用异步剪贴板API(async clipboard)的图像的编程复制和粘贴
【Web API系列】使用异步剪贴板API(async clipboard)的图像的编程复制和粘贴
39 1
|
2月前
|
前端开发 JavaScript
异步编程:由于JS是单线程执行的,所以对于耗时的操作(如网络请求),需要通过异步编程来处理。回调函数、Promise、async/await都是常用的异步编程方式。
异步编程:由于JS是单线程执行的,所以对于耗时的操作(如网络请求),需要通过异步编程来处理。回调函数、Promise、async/await都是常用的异步编程方式。
30 1
|
14天前
|
前端开发 JavaScript
JavaScript Promise
JavaScript Promise 是异步编程的一种解决方案,它表示一个尚未完成但预期在未来完成的操作的结果。Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。通过 Promise,我们可以将回调函数的嵌套改为链式调用,从而提高代码的可读性和可维护性。
9 1
|
22天前
|
前端开发 JavaScript
JavaScript中的异步编程与Promise
在现代Web开发中,JavaScript的异步编程是不可或缺的一部分。本文将介绍JavaScript中的异步编程的重要性,以及通过Promise来处理异步操作的方式,帮助读者更好地理解和应用异步编程。

相关产品

  • 云迁移中心