网络请求实战-实战Fetch和Promise相关的架构

news2025/3/10 15:46:02

目录

Promise神器(承诺)

Promise+Coding示例

Promise常见用法

简单的promise

Fetch的基本用法

fetch

Fetch基本用法

Fetch+Promise场景举例

小结


Promise神器(承诺)

Promise+Coding示例

  • 代表异步求值的过程结果

 promise链式调用,可以一直promise下去

// example 01
const promise = new Promise((resolve, reject) => {
  resolve(100)
}).then(data => {
  console.log(data)
})
// 100
// example 02
const promise = new Promise((resolve, reject) => {
  resolve(100)
}).then(data => {
  console.log(data)
  return 'abc' // 直接返回一个值
})
.then(data => { // 此处不用执行promise了,直接fulfilled了一个'abc
  console.log(data)
})
// 100 abc
// example 03
function wait(ms = 1000, data) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(data)
    }, ms)
  })
}
const promise = new Promise((resolve, reject) => {
  resolve(100)
}).then(data => {
  console.log(data) // 100
  return wait(1000, 'abc') // 等待1s,返'abc'
})
.then(data => {
  console.log(data) // 等待1000ms,打印'abc'
})
// example04
const promise = new Promise((resolve, reject) => {
  reject("some error")
}).then(data => {
  console.log("1", data) // 不执行
}).catch(ex => {
  console.error(ex) // some error
  return "GO"
}).then(data => {
  console.log(data) // GO
})
// example05
function wait(ms = 1000, data){
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(data)
    }, ms)
  })
}
async function foo(){
  console.log('--begin--')
  const one = await wait(1000, 1) 
  console.log('--tick 1--') // 等待一秒 
  const two = await wait(1000, 2)
  console.log('--tick 2--') // 再等待一秒 
  console.log(one, two) // 1, 2
  await Promise.reject('some error')
  try{
    await Promise.reject('some error')
  } catch(ex) {
    console.log(ex)  // some error
  }
}
foo()
// example 6
function wait(ms = 1000, data){
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(data)
    }, ms)
  })
}
// 工厂方法
Promise.all([wait(200, 1), wait(100, 2)])
  .then(data => {
    console.log('all', data) // 等2个promise都结束,返回这个数组[1,2]
  })
Promise.race([wait(200, 1), wait(100, 2)])
  .then(data => {
    console.log('race', data) // race是在这个执行promise数组中返回第一个拿到的值
  })
  

Promise常见用法

  • resolve & reject
  • Chain (链执行)
  • 并发和竞争(all 和 race)
  • 异常处理 (try catch)

简单的promise

const PENDING = 1
const FULLFILLED = 2
const REJECTED = 3
class Promise{
  constructor(executor){
    this.state = PENDING
    const resolver = (value) => {
      if(this.state === PENDING) {
        this.state = FULLFILLED 
        this.value = value 
      }
      for(let [onFullFill, resolve] of this.fullfills) {
        const x = onFullFill(this.value)
        resolve(x)
      }
    }
    const rejector = () => {
      this.state = REJECTED
    }
    this.fullfills = []
    executor(resolver, rejector)
  }
  then(onFullfill) {
    return new Promise((resolve, rejector) => {
      switch(this.state) {
        case FULLFILLED:
          const x = onFullfill(this.value)
          resolve(x)
          break
        case PENDING:
          this.fullfills.push([onFullfill, resolve])
          break
      }
    })
  }
}
new Promise((resolve) => {
  setTimeout(() => {
    resolve('123')
  })
}).then(data => {
  console.log(data) // 123
  return '456' 
}).then(data => {
  console.log(data) // 456
  return data
})

Fetch的基本用法

fetch

一个让处理http pipeline更容易的工具(MDN)

  • 返回Promise
  • Resolve发生在网络通信正常(404,500也是resolve)
  • Reject发生在网络通信异常
  • 默认不接受cookie(需要设置)

存在队头阻塞,服务端负载充足

Fetch基本用法

  • GET/POST/PUT/DELETE
  • Headers
  • Cookie
  • 缓存
fetch("/product", {
  method: "POST",
  headers : {
    "Content-Type" : "application/json"    
  },
  body: JSON.stringify({ name: "123苹果" }),
}).then((resp) => console.log(resp.status))
fetch("/product", {
  method: "POST",
  headers : {
    "Content-Type" : "application/json"    
  },
  body: JSON.stringify({ name: "".padStart(100000, "A")}),
}).then((resp) => console.log(resp.status))
// node端 需要引用实例
const fetch = require('node-fetch')
const promise = fetch('https://www.baidu.com', {
    method: 'POST',
    headers: {
        'Content-Type': "application/json",    
    },
    credentials: 'include', // 设置之后可以接收服务端的Cookie
})
async function foo() {
   const resp = await fetch("http://www.baidu.com", {
       headers: {
           'user-agent': "Mozillia"       
       }   
   })
   const text = await resp.text()
   console.log(text)
}
foo()
// 缓存
fetch("https://www.baidu.com", {cache: 'force-cache'})

Fetch+Promise场景举例

1.指数补偿,专门应付移动端频繁网络波动的

按照指数的时间倍数重复发送请求

  • 0ms
  • 200ms
  • 400ms
  • 800ms
  • 1600ms
  • 3200ms
  • fail
// 示例程序
const fetch = require('node-fetch')
function request(url){
  let resolved = false
  let t = 1 
  return new Promise((resolve) => {
    function doFetch(){
      if(resolved || t > 16) {
        return
      }
      
      fetch(url).then((resp) => {
        return resp.text()
      })
      .then(data => {
        if(!resolved) {
          resolved = true
          resolve(data)
          console.log('t=', t)
        }
      })
      .catch(ex => {
        console.error(ex)
      })
      setTimeout(() => {
        doFetch()
        t *= 2
      }, t * 100)
    }
    doFetch()
  })
}
request('http://www.baidu.com')
  .then(data => {
    console.log(data.length)
  })
setTimeout(() => {
}, 3000)
// 有缺陷,所有请求都发送了
function wait(ms, f) {
    return new Promise((resolve) => {
        setTimeout(()=> {
            resolve(f())        
        }, ms)    
    })
}
function request(url) {
    Promise.race([
        fetch(url),
        wait(100, ()=> fetch(url) ),
        wait(200, ()=> fetch(url) ),
        wait(400, ()=> fetch(url) ),
        wait(800, ()=> fetch(url) ),
        wait(1600, ()=> fetch(url) ),
    ])
}
request('http://www.baidu.com')
  .then(resp => {
    console.log(resp)
  })
setTimeout(() => {
}, 3000)

2.并发处理和时间窗口,底层前端请求优化的

多个资源并发请求(Promise.all)

基于时间窗口过滤重复请求

const fetch = require('node-fetch')
function hash(args) {
  return args.join(',')
}
function window_it(f, time = 50) {
  let w = {} 
  let flag = false 
  return (...args) => {// 参数传递
    return new Promise((resolve) => {
      if (!w[hash(args)]) {
        w[hash(args)] = {
          func: f,
          args,
          resolvers: [],
        }
      }
      if (!flag) {
        flag = true
        setTimeout(() => {
          Object.keys(w).forEach((key) => {
            const { func, args, resolvers } = w[key]
            const promise = func(...args)
              .then((resp) => resp.text())
              .then((text) =>
                resolvers.map((r) => {
                  r(text)
                })
              )
          })
          flag = false
        }, time)
      }
      console.log(args)
      w[hash(args)].resolvers.push(resolve)
    })
  }
}
const request = window_it(fetch, 20)
request('http://www.baidu.com')
  .then(txt => console.log(txt.length))
request('http://www.baidu.com')
  .then(txt => console.log(txt.length))
request('http://www.baidu.com')
  .then(txt => console.log(txt.length))
request('http://www.zhihu.com')
  .then(txt => console.log(txt.length))
request('http://www.baidu.com')
  .then(txt => console.log(txt.length))
request('http://www.baidu.com')
  .then(txt => console.log(txt.length))

小结

  • 为什么不教Axios? 因为fetch是浏览器提供的标准
  • 优化问题要工程化处理(所有页面的优化,请求优化,页面大小优化,白屏的优化【需要用到算法,数据结构和相关的架构知识,是针对一类问题提供工具】)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/433523.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搭建Spark Standalone集群

文章目录 一,Spark Standalone架构(一)client提交方式(二)cluster提交方式 二,Spark集群拓扑三,前提条件:安装配置了分布式Hadoop环境四,在master虚拟机上安装配置Spark&…

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(nacos)

Nacos注册中心 (一)认识和安装Nacos 1、认识Nacos 2、安装nacos 这里下载1.4.1版本 默认端口是8848 下载解压后,终端进入到nacos/bin下,bash startup.sh -m standalone 然后查看start.out文件得到一个网址就可以查看nacos的服…

《Android 移动应用基础教程(Android Studio)(第2版)》【课本习题】【学习通2023春PDF】【参考答案】

文章目录 超星学习通智能终端软件开发(基于Android Studio环境)章节作业(39)第一章第二章 Android常见界面布局第三章 Android常见界面控件第四章第五章第六章(略)第七章第八章第九章第十章第十一章第十二章…

ChatGPT常见问题,Access denied的解决办法

今天,突然想登录一登录ChatGPT,提示 Access denied, You do not have access to chat.openai.com 怎么办? “Access denied You do not have access to chat.openai.com. The site owner may have set restrictions that prevent you from ac…

leetcode142. 环形链表 II

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数…

vue3+electron开发桌面软件(7)——修改注册表,创建级联菜单

系列文章目录 系列第一篇: vue3electron开发桌面软件入门与实战(0)——创建electron应用 文章目录 系列文章目录前言一、创建右键级联菜单二、了解注册表结构1.手动添加注册表——一级菜单2.手动添加注册表——二级菜单父菜单3.手动添加注册…

IC-14W网络IC卡读写器_银河麒麟桌面操作系统V10适配测试报告

银河麒麟操作系统产品NeoCertify 认证测试报告 系统版本:银河麒麟桌面操作系统V10 厂商名称: 广州荣士电子有限公司 认证产品:IC-14W网络IC卡读写器 测试日期: 2022-11-04 …

基于SVG的HMI组件

人机界面是自动化领域不可或缺重要组成部分。人机界面系统的设计看上去并没有太大的技术门槛,但是设计一个HMI系统的工作量是巨大的,如果你没有足够的耐心和精力是难以完成一个通用HMI系统的。构建UI控件库就是一个似乎永远完不成的事情,用户…

12.基于蒙特卡洛抽样的电动汽车充电负荷计算

说明书 MATLAB代码:基于蒙特卡洛抽样的电动汽车充电负荷计算 关键词:电动汽车 蒙特卡洛模拟 抽样 充放电负荷 参考文档:《主动配电网多源协同运行优化研究_乔珊》第3.2节,完全复现 仿真平台:MATLAB 优势&#xf…

JavaWeb——IO、存储、硬盘、文件系统相关常识

目录 一、IO 1、定义 二、存储和硬盘 1、存储 2、硬盘 三、文件系统 1、文件 (1)、定义 (2)、分类 (3)、操作 2、树形结构和目录 3、路径 (1)、定义 (2&…

elementui是怎么做表单验证的?

文章目录 前言elementui是怎么做表单验证?步骤 一、 表单验证校验代码?二、el-button提交验证代码2.validate方法深入了解1. 有参数2. 无参数 总结 前言 在项目开发中,我们经常会遇到表单保存的功能,在表单保存前,常常…

Salesforce如何防止黑客攻击和数据泄露?了解他们的安全措施!

安全性一直是Salesforce密切关注的问题。Google的安全浏览报告指出,2022年网络钓鱼网站的数量增加了80%。面对着黑客攻击、安全漏洞、数据泄露等不安全事件频发,实施更强大的安全措施比以往更加重要。 调查显示,电子邮件目前是网…

阿里巴巴图标,font-family字体样式

阿里巴巴官网:https://www.iconfont.cn/ 如有需要,请注意到文章最后的问题。 一,图标 1,搜索关键词,点击图标 -> 加入购物车 -> 添加到项目 2,两种方式 (1)选择 Font cla…

推荐一个好工具,可以替代 swagger 生成文档

Swagger 是一个规范且完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。 Swagger 的目标是对 REST API 定义一个标准且和语言无关的接口,可以让人和计算机拥有无须访问源码、文档或网络流量监测就可以发现和理解服务的能力。当通过 S…

SpringBoot扫包排除指定包(配置文件形式)

1、背景​ 在有些时候,不同环境可能需要用代码不同模块的能力,但是不同环境的项目包是一致的。这块我们想到的最简单的办法是在maven打包的时候打不同的模块,但是这样往往需要出多个包,虽然这种方式是正路但运维同学嫌麻烦。第二种…

Java面试题--MySQL索引

一. 索引介绍 MySQL的索引是一种数据结构,它可以帮助MySQL快速定位需要访问的记录。索引可类比于一本书的目录,通过它可以快速找到某个特定的记录。 MySQL支持多种类型的索引,每种索引都有其优势和局限性,常用的包括&#xff1a…

python类型转换

我们就想那我们目前接触到的三种类型做一下转换 分别是 字符串 浮点数 正整数 可能会有刚接触编程的小伙伴在想 没事类型转换什么呢? 其实在实际开发中 这东西用的不要太多 根据我们目前认识的类型 先用到三个方法 我们编写代码 String_int str(111); print(St…

初阶数据结构——时间复杂度和空间复杂度

目录 算法效率算法的复杂度 时间复杂度时间复杂度的概念习题 空间复杂度空间复杂度的概念习题 什么是数据结构? 数据结构(Data Structure)是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。 什么是算法? 算法…

java+ssm603企业人事档案管理系统带前端springboot

人事管理系统的设计与实现采用Spring、SpringMVC和MyBatis作为主体框架,系统设计遵循界面层、业务逻辑层和数据访问层的Web开发三层架构。采用B/S结构,使得系统更加容易维护。人事管理系统的设计与实现主要实现角色有管理员和用户,管理员在后台管理资料文件模块、员工模块、文件…

深度相机初体验:Hello World

当我的组长给了我一个深度相机,倒霉的事情就开始了,在使用的过程中遇到的某些问题搜不到,头秃啊呜呜呜呜呜呜呜呜 配置: ubuntu20.04(我实在是懒得去升级了,一旦升级就可能会出现找不到教程的可能性&#x…