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)
    } )


相关文章
|
14天前
|
前端开发 JavaScript 开发者
Async 和 Await 是基于 Promise 实现
【10月更文挑战第30天】Async和Await是基于Promise实现的语法糖,它们通过简洁的语法形式,借助Promise的异步处理机制,为JavaScript开发者提供了一种更优雅、更易于理解和维护的异步编程方式。
22 1
|
14天前
|
JSON 前端开发 JavaScript
浅谈JavaScript中的Promise、Async和Await
【10月更文挑战第30天】Promise、Async和Await是JavaScript中强大的异步编程工具,它们各自具有独特的优势和适用场景,开发者可以根据具体的项目需求和代码风格选择合适的方式来处理异步操作,从而编写出更加高效、可读和易于维护的JavaScript代码。
21 1
|
1月前
|
前端开发 JavaScript
setTimeout、Promise、Async/Await 的区别
`setTimeout` 是用于延迟执行函数的简单方法;`Promise` 表示异步操作的最终完成或失败;`Async/Await` 是基于 Promise 的语法糖,使异步代码更易读和维护。三者都用于处理异步操作,但使用场景和语法有所不同。
|
1月前
|
前端开发 JavaScript 开发者
JavaScript 中的异步编程:深入了解 Promise 和 async/await
【10月更文挑战第8天】JavaScript 中的异步编程:深入了解 Promise 和 async/await
|
1月前
|
前端开发 JavaScript UED
深入了解JavaScript异步编程:回调、Promise与async/await
【10月更文挑战第11天】深入了解JavaScript异步编程:回调、Promise与async/await
15 0
|
2月前
|
前端开发 JavaScript
解决异步问题,教你如何写出优雅的promise和async/await,告别callback回调地狱!
该文章教授了如何使用Promise和async/await来解决异步编程问题,从而避免回调地狱,使代码更加清晰和易于管理。
解决异步问题,教你如何写出优雅的promise和async/await,告别callback回调地狱!
|
3月前
|
前端开发 JavaScript 开发者
探索前端开发中的异步编程:Promise与Async/Await
在现代前端开发中,处理异步操作是至关重要的。本文将深入探讨异步编程的核心概念,重点比较JavaScript中的Promise与Async/Await两种异步编程方式。通过实例和比较,读者将能够理解这两种方法的优缺点,如何在实际开发中选择适合的异步编程模式,从而编写更简洁、可维护的代码。
|
API 计算机视觉
MLDL之API:关于各国内外大平台API简介、使用方法之详细攻略
MLDL之API:关于各国内外大平台API简介、使用方法之详细攻略
|
6天前
|
JSON API 数据格式
淘宝 / 天猫官方商品 / 订单订单 API 接口丨商品上传接口对接步骤
要对接淘宝/天猫官方商品或订单API,需先注册淘宝开放平台账号,创建应用获取App Key和App Secret。之后,详细阅读API文档,了解接口功能及权限要求,编写认证、构建请求、发送请求和处理响应的代码。最后,在沙箱环境中测试与调试,确保API调用的正确性和稳定性。
|
18天前
|
供应链 数据挖掘 API
电商API接口介绍——sku接口概述
商品SKU(Stock Keeping Unit)接口是电商API接口中的一种,专门用于获取商品的SKU信息。SKU是库存量单位,用于区分同一商品的不同规格、颜色、尺寸等属性。通过商品SKU接口,开发者可以获取商品的SKU列表、SKU属性、库存数量等详细信息。

热门文章

最新文章