IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 前端 JavaScript 之 Promise _ 前后版 -> 正文阅读

[JavaScript知识库]前端 JavaScript 之 Promise _ 前后版

目录

1.?回调函数?callback

2.?回调地狱

3.?认识?Promise

4.?Promise 的进阶语法

5.?async?函数?和?await?关键字

Promise 简图 :


1.?回调函数?callback

??+?一种封装代码的手段

??+?什么是?callback?,?概念

????=>?把?函数A?当做?实参?传递到?函数B?内部

????=>?在?函数B?内部以?形参?的方式?调用?函数A

????=>?我们管这个行为叫做?回调函数

????=>?我们说?函数A?是?函数B?的 回调函数

function A() {
  console.log('我是 A 函数')
}

function B(fn) {
  // 此时 fn 形参接受的是书写在 B() 的时候, () 内部的内容 : A
  // 此时 fn 形参接受的就是全局 函数 A 的地址
  // 此时 fn 形参和全局变量 A 操作一个函数空间
  console.log('我是 B 函数')
  // 调用 fn 其实就是在调用执行全局的 A 函数
  fn()
}
// 调用 B 函数
// A 是一个保存 函数的地址
// 把 函数 A 这个地址当做实参传递给了 B 函数内部的 fn 形参
B(A)
// 函数A?是?函数B?的回调函数

??+?为什么需要?callback?回调函数

??+?如果从头到尾都是 同步代码,?不需要回调函数

????=>?当你在 封装代码 的时候

????=>?并且代码内有 异步 的时候

????=>?并且需要在?异步的?末尾?做一些事情的时候

????=>?使用?callback

解释:?为什么异步的末尾封装要使用?callback

??+?因为?JS?的单线程

??+?同一个时间点只能做一个事情

??+?主要:?异步的结束时间不确定

??+?例子:?外卖

????=>?一个外卖员同一个时间点只能做一件事情

????=>?如果你希望多带一双筷子

????=>?方案1:?等到外卖员刚好到达店里的时候,?给他打电话

????=>?方案2:?在点餐的时候给一个备注


????回调函数的缺点:

??+?回调地狱

??+?当回调 嵌套 回调的时候,?代码的阅读和可维护性不高

??解决回调地狱的问题:

??+?Promise?来解决回调地狱

??+?分析:

????=>?Promise?是来解决回调地狱

????=>?回调地狱,?是因为回调函数嵌套过多

????=>?回调函数,?为了解决在异步末尾做一些事情的封装

????=>?Promise?就是一种优雅的对于异步代码封装的方案

// 为什么需要回调函数
// 封装一段代码
// 例子 : 外卖公司做好的事情
function waimai(beizhu) {
  // 获取一个 1000 ~ 6000 的随机整数
  const time = 1000 * Math.round(Math.random() * 5 + 1)
  console.log(' 在路上 ' + time)
  // 我们使用 setTimeout 模拟一个网络环境请求
  setTimeout(() => {
    console.log('到达店里了, 拿到外卖')
    // 直接把我需要执行的代码放在这个位置
    // 那么这个封装就没有意义了
    // 就需要用到回调函数了
    // 因为这个位置是异步的末尾了
    // 这个位置调用 beizhu 就是在异步的末尾调用
    // 例 : 不管什么时候到了店里
    // 拿到外卖以后, 把 备注 的内容执行一下
    beizhu()
  }, time)
}
// 用户的需求: 想多拿一双筷子
waimai(function () { console.log('多拿一双筷子') })
// 用户的需求: 想多拿点辣椒
waimai(function () { console.log('多拿点辣椒') })

?


2.?回调地狱

??+?一种使用回调函数封装的代码时候的情况

??+?回调函数的使用是有 函数嵌套 在里面的

??+?当你大量使用回调函数封装的代码的时候,?会出现 结构紊乱

????=>?不利于代码的阅读和维护

??+?为了解决回调地狱

????=>?ES6?的语法内出现了一个新的语法,?叫做?Promise

????=>?为了把?异步代码?封装变成?Promise?语法的封装

????=>?不在使用?回调函数?来封装?异步代码了

????=>?本质: 用来?封装异步代码?

?实现需求?:

1.?发送一个请求,?请求一个接口

??=>?等到响应回来以后

??=>?把内容打印在控制台

2.?发送第二个请求,?请求第二个接口

??=>?要求必须要在第一个请求结束以后,?打印完毕以后再次发送请求

??=>?把响应内容打印在控制台

3.?发送第三个请求,?请求第三个接口

??=>?要求,?必须要在第二个请求结束以后,?打印完毕以后再次发送请求

??=>?把响应内容打印在控制台

+?问题1:?在什么位置发送第二个请求??

=>?ajax?是同步还是异步,?异步的

=>?打开页面,?会马上把第一个请求发送出去

=>?第一个请求还没有回来的时候,?继续发送了第二个请求

=>?因为第一个请求的?success?一定会在请求结束后才执行

=>?我需要把第二个请求的代码放在第一个请求的?success?内部

问题:?代码的阅读和可维护性不高

+?代码嵌套过多

// 实现需求 1 :
ajax({
  url: 'http://localhost:8888/test/first',
  success: function (res) {
    console.log('第一次请求的结果')
    console.log(res)
    // 实现需求 2 :
	  // 第一个请求结束以后, 才会执行这个位置的代码
	  // 这个时候才会把第二个请求发送出去
    ajax({
      url: 'http://localhost:8888/test/second',
      dataType: 'json',
      success: function (res) {
        console.log('第二次请求的结果')
        console.log(res)
        // 实现需求 3 :
		    // 因为第二个请求结束以后, 才会执行这个位置的代码
		    // 这个时候才会把第三个请求发送出去
        ajax({
          url: 'http://localhost:8888/test/third',
          data: 'name=Jack&age=18',
          dataType: 'json',
          success: function (res) {
            console.log('第三次请求的结果')
            console.log(res)
          }
        })
      }
    })
  }
})

3.?认识?Promise

+?是一个?ES6?出现的语法

+?Promise?也是一个?JS?内置的 构造函数

promise - 承诺 :
+ 承诺的状态有多少个 ?
? => 继续(持续执行过程中)
? => 成功
? => 失败
+ 承诺状态之间的转换 : 只能转换一次
? => 要么是 继续 转换成 成功
? => 要么是 继续 转换成 失败
+ Promise 也有三个状态
? => 继续: pending
? => 成功: fulfilled
? => 失败: rejected?

const p = new Promise(function (resolve, reject) {
  // ...
  // ...
})
p.then(function () {
  // ...
})
p.catch(function () {
  // ...
})

Promise?的基础语法 :

??=>?const?p?=?new?Promise(function?a( )?{

????//?你要封装的异步代码

??})

??=>?promise?对象可以调用两个方法

????1.?p.then(function?( )?{ })

????2.?p.catch(function?( )?{ })

??+?promise对象.then(function?( )?{?...?})

????=>?给当前这个承诺注册一个?成功以后的函数

??+?promise对象.catch(function?( )?{?...?})

????=>?给当前这个承诺注册一个?失败以后的函数

??如何改变?promise?的状态

??+?在?new?Promise?的?a?函数内

??+?可以接受两个参数

????1.?第一个参数:?可以将该?Promise?的状态由继续转换为?成功

????2.?第二个参数:?可以将该?Promise?的状态由继续转换为?失败

// 1. 异步代码
const p = new Promise(function (resolve, reject) {
  // resolve 就是一个转换成功的方法
  // 当你书写 resolve() 的时候, 就是在把 该 promise 的状态转换为成功
  // 就会执行 .then 时候里面书写的 b 函数
  // reject 就是一个转换成失败的方法
  // 当你书写 reject() 的时候, 就是在把 该 promise 的状态转换为失败
  // 就会执行 .catch 时候里面书写的 c 函数
  // 这两个只能书写一个

  // 书写你需要封装的异步代码
  const time = 1000 * Math.round(Math.random() * 5 + 1)
  console.log('承诺一辈子在一起')
  setTimeout(() => {
    // 下面代码一旦执行, 就会把 promise 的状态改成成功
    // resolve()
    // 下面代码一旦执行, 就会把 promise 的状态改成失败
    // reject()
    if (time >= 3000) {
      // 因为会转换为成功 => 两人去世, 埋一个坟
      // 通知一下, 你该烧纸了
      // resolve() 调用的是 then 内部的函数 b
      // 所以这里书写在 () 内部的 time 内容就是给到 then 内 b 的实参
      resolve(time)
    } else {
      // 当做失败, 表示离婚
      // 通知一下, 该去炸坟了
      // reject() 调用的是 catch 内部的函数 c
      // 所以这里书写在 () 内部的 time 内容就是给到 catch 内 c 的实参, 也是报错信息
      reject(time)
    }
  }, time)
})
// promise 对象调用的两个方法
// 注册 成功
p.then(function b(t) {
  // 函数 b 不会被直接调用的
  // 这个位置的代码会在 p 这个 promise 的状态由 继续 转换为 成功 的时候调用执行
  console.log(t, '成功的函数 b')
  // t 就是你在 promise 内部书写的 resolve 的小括号里面 time 的内容
})
// 注册 失败
p.catch(function c(err) {
  // 函数 c 不会被直接调用
  // 这个位置的代码会在 p 这个 promise 的状态由 继续 转换为 失败 的时候调用执行
  console.log(err, '失败的函数 c')
})

?


4.?Promise 的进阶语法

+?当一个?Promise?的?then?内的代码

+?只要你在前一个?then?内部以?return?返回一个新的?promise?对象?的时候

+?新?promise?对象的?then?可以直接在前一个?then?的后面继续书写?then

?需求:

??1.?发送一个请求, 请求第一个接口

??2.?发送第二个请求, 请求第二个接口

????=>?前提:?必须要等到第一个请求结束以后再次发送

// 初始版 : 
// 需求 1 :
const p = new Promise(function (resolve, reject) {
  // 做异步的事情
  ajax({
    url: 'http://localhost:8888/test/first',
    success: function (res) {
      // 第一个请求成功了
      // res 就是后端给出的结果
      resolve(res)
    }
  })
})
p.then(function (res) {
  console.log('第一次请求结束了')
  console.log(res)
  // 需求2:
  const p2 = new Promise((resolve, reject) => {
    // 做异步的事情
    ajax({
      url: 'http://localhost:8888/test/second',
      dataType: 'json',
      success: function (res) {
        // 第一个请求成功了
        // res 就是后端给出的结果
        resolve(res)
      }
    })
  })
  p2.then(res => {
    console.log('第二个请求结束了')
    console.log(res)
  })
})
// 进阶版 :
const p = new Promise((resolve, reject) => {
  // 做异步的事情
  ajax({
    url: 'http://localhost:8888/test/first',
    success: function (res) {
      resolve(res)
    }
  })
})
// 向拿到 p 的 resolve 的结果
// 就得写 p.then()
p
  .then(function (res) {
    console.log('第一次请求的结果')
    console.log(res)
    // 做第二个事情
    const p2 = new Promise((resolve, reject) => {
      ajax({
        url: 'http://localhost:8888/test/second',
        dataType: 'json',
        success: function (res) {
          resolve(res)
        }
      })
    })

    // 在第一个 then 内部 return 一个 新的 promise 对象 p2
    return p2
  })
  .then(res => {
    console.log('第二次的请求结果')
    console.log(res)
  })

// 使用我按照 promise 形式封装的 pAjax 函数来完成
pAjax({ url: 'http://localhost:8888/test/first' })
  .then(res => {
    console.log('第一个请求结束了')
    console.log(res)

    // return 一个新的 promise 对象
    return pAjax({
      url: 'http://localhost:8888/test/second',
      dataType: 'json'
    })
  })
  .then(res => {
    console.log('第二个请求结果')
    console.log(res)

    // return 一个新的 promise 对象
    return pAjax({
      url: 'http://localhost:8888/test/third',
      data: 'name=Jack&age=20',
      dataType: 'json'
    })
  })
  .then(res => {
    console.log('第三次请求的结果')
    console.log(res)
  })

5.?async?函数?和?await?关键字

?+?ES7?~?ES8?之间出现的语法

+?作用?:

+?为了解决?Promise?的问题?,?把?Promise?的代码书写的更优雅

+?核心作用:?把?异步代码?写的?看起来像?同步代码,?本质还是异步

语法:

??=>?async?关键字?(异步)

??+?使用:?书写在函数的前面

??(可以是声明式函数,?可以是函数表达式,?可以是箭头函数)

????=>?async?function?( )?{ }

????=>?async?( )?=>?{ }

??+?作用:

????1.?该函数内可以使用?await?关键字了

????2.?会把该函数变成一个?异步函数,?只是叫做?异步函数

????(这个异步函数并不是我们真实的异步代码,只是给这个函数起了个名字)

??????=>?影响的是函数内部的代码?,?不影响函数外面的代码

// async 的语法
async function fn() {}
const fn = async function () {}
const fn = async a => {}

=>?await?关键字?(等待)

??+?要求:

????1.?await?必须写在一个有?async?关键字的异步函数内部

????2.?await?后面等待的内容必须是一个?promise?对象?,?否则等不了

??+?作用:

????=>?把?promise?中本该在?then?内代码接受的结果?,?

????可以直接在?await?前面定义变量接受

????=>?后续的代码需要等到?promise?执行完毕才会执行

console.log('start')	// ① start
async function fn() {
  console.log('我是 fn 函数内部的代码')	// ②
  // 因为 pAjax 是按照 promise 的语法形式进行封装的代码
  // pAjax 会返回一个 promise 对象
  // fn 函数内, 执行到 pAjax 这个代码的时候
  // 会等待, 等到这个异步的代码完全执行完毕, 把结果赋值给 r1 以后
  // 在继续执行后面的代码
  const r1 = await pAjax({ url: 'http://localhost:8888/test/first' })
  console.log(r1)	// ④
}
fn()
console.log('end')	// ③ end

console.log('start')  // 一 : start
async function fn() {
  // 此时 fn 函数内可以使用 await 关键字了
  // pAjax 返回出来的 promise 对象会执行
  // 把 resolve() 的时候 括号里面的内容 赋值给 r1. 在继续向后执行代码
  const r1 = await pAjax({ url: 'http://localhost:8888/test/first' })
  console.log(r1)   // 三 : 
  // 实现需求2:
  const r2 = await pAjax({
    url: 'http://localhost:8888/test/second',
    dataType: 'json'
  })
  console.log(r2)   // 四 : 
  // 实现需求3:
  const r3 = await pAjax({
    url: 'http://localhost:8888/test/third',
    data: 'name=Jack&age=20',
    dataType: 'json'
  })
  console.log(r3)   // 五 : 
}
fn()
console.log('end')  // 二 : end

Promise 简图 :

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-02 10:43:22  更:2021-08-02 10:43:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 12:31:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码