Ajax第四天

文章详细阐述了JavaScript中的异步编程概念,包括async函数和await关键字的使用,以及事件循环(EventLoop)的工作原理,如宏任务和微任务的执行顺序。文中通过示例解释了如何在async函数中使用await等待Promise的结果,并讨论了它们在任务队列和事件循环中的位置和影响。
摘要由CSDN通过智能技术生成

async 和 await

async 和 await 的基本使用

1、async用于修饰一个函数,表示一个函数异步的

如果async函数内没有await,那么async没有意义,全是同步内容

只有遇到了await开始往下,才是异步的开始

2、await 要用在 async 函数中

3、await 后面一般会跟一个promise对象,await会阻塞async函数的执行,

直到等到promise成功的结果(resolve的结果)

4、await 只会等待 promise 成功的结果,如果失败了会报错,需要 try catch

事件循环队列-宏任务微任务

 JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。

        为了协调事件、用户交互、脚本、UI 渲染和网络处理等行为,防止主线程的不阻塞,Event Loop 的方案应用而生。Event Loop 包含两类:一类是基于 Browsing Context,一种是基于 Worker。

        二者的运行是独立的,也就是说,每一个 JavaScript 运行的"线程环境"都有一个独立的 Event Loop,每一个 Web Worker 也有一个独立的 Event Loop。

宏任务:


        setTimeout setInterval Ajax DOM事件  script(整体代码)   I/OUI交互事件   postMessageMessage  Channel setImmediate(Node.js 环境)

微任务:


        Promise async/await  Object.observe MutationObserver    process.nextTick(Node.js 环境)

微任务比宏任务的执行时间要早

        异步和单线程

        异步和单线程是相辅相成的,js是一门单线程脚本语言,所以需要异步来辅助

异步和同步的区别:


        异步不会阻塞程序的执行,

        同步会阻塞程序的执行,

前端使用异步的场景:

定时任务

        setTimeout,setInverval

网络请求:

        ajax请求,动态<img>加载

        事件绑定

任务队列和event loop(事件循环)


        1)所有的同步任务都在主线程上执行,行成一个执行栈。

        2)除了主线程之外,还存在一个任务列队,只要异步任务有了运行结果,就在任务列队中植入一个时间标记。

        3)主线程完成所有任务(执行栈清空),就会读取任务列队,先执行微任务队列在执行宏任务队列。

        4)重复上面三步。

        只要主线程空了,就会读取任务列队,这就是js的运行机制,也被称为 event loop(事件循环)。


考察的是事件循环和回调队列。注意以下几点:

Promise 优先于 setTimeout 宏任务,所以 setTimeout 回调会最后执行

        Promise 一旦被定义就会立即执行

        Promise 的 resolve 和 reject  是异步执行的回调。所以 resolve() 会被放到回调队列中,在主函数执行完和 setTimeout 之前调用

        await 执行完后,会让出线程。async 标记的函数会返回一个 Promise 对象

解析:
        首先,事件循环从宏任务(macrostack)队列开始,这个时候,宏任务队列中,只有一个 script (整体代码)任务。从宏任务队列中取出一个任务来执行。

        首先执行 console.log('script start'),输出 ‘script start'

        遇到 setTimeout 把 console.log('setTimeout') 放到 macrotask 队列中

        执行 aync1() 输出 ‘async1 start' 和 'async2' ,把 console.log('async1 end') 放到 micro 队列中

        执行到 promise ,输出 'promise1' ,把 console.log('promise2') 放到  micro 队列中

        执行 console.log('script end'),输出 ‘script end'

        macrotask 执行完成会执行 microtask ,把 microtask quene 里面的 microtask 全部拿出来一次性执行完,所以会输出 'async1 end' 和 ‘promise2'

        开始新一轮的事件循环,去除执行一个 macrotask 执行,所以会输出 ‘setTimeout'

个人设置案例

<!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>
  <link rel="stylesheet" href="./css/bootstrap.min.css" />
  <style>
    .form-select {
      width: 103px;
      display: inline-block;
    }

    .col-form-label {
      text-align: right;
    }

    .figure-img {
      width: 100px;
      height: 100px;
      cursor: pointer;
    }

    #upload {
      display: none;
    }
  </style>
</head>

<body>
  <div class="container">
    <h1 class="p-5">个人设置</h1>
    <form class="col-6">
      <div class="row mb-3">
        <label class="col-form-label col-3">昵称:</label>
        <div class="col-9">
          <input class="form-control col-9" type="text" name="nickname" />
        </div>
      </div>
      <div class="row mb-3">
        <label class="col-form-label col-3">籍贯:</label>
        <div class="col-9">
          <select class="form-select col-4" name="province">
            <option value="">--省--</option>
          </select>
          <select class="form-select col-4" name="city">
            <option value="">--市--</option>
          </select>
          <select class="form-select col-4" name="area">
            <option value="">--区--</option>
          </select>
        </div>
      </div>
      <div class="row mb-3">
        <label class="col-form-label col-3">头像:</label>
        <div class="col-9">
          <input class="form-control col-9" type="hidden" name="avatar" />
          <figure class="figure">
            <input type="file" id="upload" />
            <img src="https://yanxuan-item.nosdn.127.net/12a882699bd531a1bd428bffe1989525.jpg"
              class="figure-img img-fluid rounded" alt="..." />
            <figcaption class="figure-caption">修改头像</figcaption>
          </figure>
        </div>
      </div>
      <div class="row mb-3">
        <label class="col-3"></label>
        <div class="col-9">
          <button class="btn btn-primary">保存</button>
        </div>
      </div>
    </form>
  </div>

  <script src="./lib/bootstrap.min.js"></script>
  <script src="./lib/axios.js"></script>
  <script src="./lib/form-serialize.js"></script>
  <script>
    // 在线接口文档:https://www.showdoc.com.cn/1834761734600444/8477923164668939


    // 配置请求根路径
    axios.defaults.baseURL = 'http://ajax-api.itheima.net'

    // 昵称
    let nameInput = document.querySelector('[name=nickname]')

    // 头像
    let upload = document.querySelector('#upload')
    let avatarImg = document.querySelector('.figure img')
    // 隐藏域
    let hiddenAvatar = document.querySelector('[name=avatar]')

    // 省市区
    let form = document.querySelector('form')
    let provinceSelect = document.querySelector('[name=province]')
    let citySelect = document.querySelector('[name=city]')
    let areaSelect = document.querySelector('[name=area]')


    // ========================================= 渲染展示功能 =========================================
    // 获取数据结果,展示到页面中
    ;(async function () {
      const {data: res} = await axios.get('/api/settings')
      console.log(res);
      const {nickname, area, avatar, city, province} = res.data
      // 昵称
      nameInput.value = nickname
      // 省市区

      // 2、获取省市区的数据据并渲染
      // 2.1获取省渲染
      const {data: provinceRes} = await axios.get('/api/province')
      console.log(provinceRes);
      const provinceStr = provinceRes.data.map(item => `<option value="${item}">${item}</option>`).join('')
      provinceSelect.innerHTML = `<option value="">--省--</option>${provinceStr}`

      // 获取市 渲染
      const {data: cityRes} = await axios.get('/api/city',{
        params:{
          pname: province
        }
      })
      console.log(cityRes);
      const cityStr = cityRes.data.map(item => `<option value="${item}">${item}</option>`).join('')
      citySelect.innerHTML = `<option value="">--市--</option>${cityStr}`


      // 地区
      const {data: areaRes} = await axios.get('/api/area',{
        params:{
          pname: province,
          cname: city
        }
      })
      console.log(areaRes);
      const areaStr = areaRes.data.map(item => `<option value="${item}">${item}</option>`).join('')
      areaSelect.innerHTML = `<option value="">--区--</option>${areaStr}`




      provinceSelect.value = province
      citySelect.value = city
      areaSelect.value = area
      // 头像
      avatarImg.src = avatar

      hiddenAvatar.value = avatar
    })()


    // ========================================= 省市切换功能 =========================================
    // 省切换
    provinceSelect.addEventListener('change', async function() {
      // 获取当前选择的省
      // console.log(provinceSelect.value);


      // 1、获取市的数据
      // 获取市 渲染
      const {data: cityRes} = await axios.get('/api/city',{
        params:{
          pname: this.value
        }
      })
      console.log(cityRes);
      const cityStr = cityRes.data.map(item => `<option value="${item}">${item}</option>`).join('')
      citySelect.innerHTML = `<option value="">--市--</option>${cityStr}`
      areaSelect.innerHTML = `<option value="">--区--</option>`
      
    })

    // 市切换
    citySelect.addEventListener('change', async function() {
       // 地区
      const {data: areaRes} = await axios.get('/api/area',{
        params:{
          pname: provinceSelect.value,
          cname: this.value
        }
      })
      console.log(areaRes);
      const areaStr = areaRes.data.map(item => `<option value="${item}">${item}</option>`).join('')
      areaSelect.innerHTML = `<option value="">--区--</option>${areaStr}`


    })



    // ========================================= 头像上传功能 =========================================
    // 点击图片,模拟点击文件域
    avatarImg.addEventListener('click', function() { upload.click() })


    // 头像change
    // 1、注册change事件
    // 2、获取文件 参数 数据 this.files[0]
    // 3、创建 fd 实例 FormData
    // 4、fd.append('', )
    // 5、发送数据
    upload.addEventListener('change', async function() {
      console.log(this.files[0]);
      const fd = new FormData()
      fd.append('avatar', this.files[0])

      const {data: res} = await axios.post('/api/file', fd)
      console.log(res);

      // 6、更改图片
      avatarImg.src = res.data.url

      // 7、将地址保存在隐藏域
      hiddenAvatar.value = res.data.url
    }) 



    // ========================================= 保存功能 ========================================= 
    // 1、监听 提交事件
    // 2、阻止默认行为
    // 3、处理数据
    // 4、发送请求
    form.addEventListener('submit', async function(e) {
      e.preventDefault()
      // 因为 serialize 不能获取 img 标签上的数据 所以需要 将 img 上的 src 值 保存在input 的value中才能获取
      // 又因为这个input 框仅仅是用来保存数据的 所以 需要隐藏 隐藏域


      const data = serialize(this, {hash: true})
      console.log(data);

      const {data: res} = await axios.put('/api/settings', data)
     console.log(res); 
     alert(res.message)
    })

  </script>
</body>

</html>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值