代码编织梦想

一.async和await

1.async和await语法

2.async和await注意事项

二.使用async和await优化回调地狱

三.EventLoop事件循环

四.微任务和宏任务

1.异步任务

2.微任务队列和宏任务队列

五.个人信息修改模板(附带头像上传)

六.自测题Ajax


一.async和await

1.async和await语法

async function 函数名() {
    const result = await Promise对象
    // 拿到Promise对象内成功的结果继续向下执行
}

示例: 


// 用await取代then函数, 来提取成功的值在原地
let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('成功的值')
    }, 2000)
})

// 普通函数: async+await
async function fn() {
    const result = await p
    console.log(result)
}
fn()

// 箭头函数: async+await
const myFn = async () => {
    const result = await p
    console.log(result)
}
myFn()

async和await的作用是:取代then函数, 来提取Promise的值

2.async和await注意事项

await 必须用在async修饰的函数内

// 1. await必须用在被async修饰的函数内, 函数内无await, 则async可省略
// 报错: await is only valid in async functions
function myFn() {
    const res = await 1
}
myFn()

async修饰后, 此函数为异步函数

 // 在此函数内, 遇到await会暂停代码往下, 但不影响外面继续执行同步流程
// 等所有主线程同步代码走完, 再执行await并继续向下
console.log(1);
async function myFn() {
    console.log(2);
    const res = await 3
    console.log(res);
    console.log(4);
}
console.log(5);
myFn()
console.log(6);

await之后一般跟promise

await后面一般跟Promise对象
// 如果跟的是非Promise对象, 则等待所有同步代码执行后, 把此结果作为成功的结果留在原地使用
// 如果是Promise对象, 则等待Promise对象内触发resolve返回成功结果, 在原地使用
let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(1)
    }, 2000)
})

console.log(1);
async function myFn() {
    console.log(2);
    const res = await p
    console.log(res);
    console.log(4);
}
console.log(5);
myFn()
console.log(6);

await不能捕获失败结果, 需要使用try+catch关键字捕获

/*
    try和catch语法
    try {
        // 这里放可能在执行中报错的代码
        // 如果报错会终止代码继续执行, 直接跳转进catch里执行
    } catch (err) {
        // err接收try大括号内报错抛出的异常代码
    }

*/
let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        // resolve(1)
        reject(new Error('失败'))
    }, 2000)
})

async function myFn() {
    try {
        const res = await p
        console.log(res);
    } catch (err) {
        console.error(err)
    }
}
myFn()

二.使用async和await优化回调地狱

改进前

// 使用Promise的链式调用解决问题
// axios函数在原地返回的就是一个Promise对象
let pname = ''
axios.get('http://ajax-api.itheima.net/api/province').then(res => {
    // 2. 获取某个省, 对应的城市列表
    pname = res.data.data[5];
    return axios.get(`http://ajax-api.itheima.net/api/city?pname=${pname}`)
}).then(res => {
    // 3. 获取某个市, 对应的地区列表
    let cname = res.data.data[0]
    return axios.get(`http://ajax-api.itheima.net/api/area?pname=${pname}&cname=${cname}`)
}).then(res => {
    console.log(res);
})

改进后

// 使用Promise的链式调用解决问题
// axios函数在原地返回的就是一个Promise对象
async function f() {
  const provinces = await axios.get('http://ajax-api.itheima.net/api/province')
  const pname = provinces.data.data[5]
  const citys = await axios.get(`http://ajax-api.itheima.net/api/city?pname=${pname}`)
  const cname = citys.data.data[0]
  const areas = await axios.get(`http://ajax-api.itheima.net/api/area?pname=${pname}&cname=${cname}`)
	return areas
}
f()

三.EventLoop事件循环

浏览器中的EventLoop(这个比较偏理论一点,我是这样理解的):js是单线程的,一次只能做一件事。js在浏览器这个宿主环境中运行。浏览器是多线程的,用户交互,定时器,网络请求等等浏览器中的事件会产生对应的任务,任务多了要在任务队列中排队,浏览器的主线程依次取出任务来执行,此过程不断重复从而形成一个循环,称为EventLoop。

JavaScript 是一门单线程执行的脚本语言。也就是说,同一时间只能做一件事情。

javaScript要运行在宿主环境中(浏览器,nodejs)下。浏览器内部有执行js代码的引擎(V8引擎)

浏览器事件循环:

排队是任务是以事件及其回调的方式存在的。

当事件(用户的点击,图片的成功加载)发生时,将其回调添加到任务队列;主线程上的任务完成之后,就会从任务队列中取出任务来执行

四.微任务和宏任务

1.异步任务

不是马上执行,是放入到队列中等待;

如果所有的任务都要按序等待,那么也不行,需要有一个能插队的机制。所以又将异步任务分为微任务和宏任务,同时对应微任务队列和宏任务队列。

当主线程空闲时,先执行微任务队列中的任务,再去执行宏任务队列中的任务。

2.微任务队列和宏任务队列

微任务代码(js语法)

  • Promise对象.then()

宏任务代码(宿主环境)

  • script
  • dom事件
  • ajax
  • setTimout

五.个人信息修改模板(附带头像上传)

完成案例效果图:

 HTML和CSS代码:


<!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>08.案例_个人信息修改</title>
  <link rel="stylesheet" href="https://unpkg.com/bootstrap@5.1.3/dist/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="https://unpkg.com/bootstrap@5.1.3/dist/js/bootstrap.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/axios@0.27.2/dist/axios.min.js"></script>
  <script src="./lib/form-serialize.js"></script>
 
</body>

</html>

落地js代码:

  //渲染个人信息
  <script>
        axios.defaults.baseURL = 'http://ajax-api.itheima.net'

        // 封装函数document.querySelector('#' + id)
        function $(id) {
            return document.querySelector('#' + id)
        }

        async function getInfo() {
            const res = await axios.get('/api/settings')
            const obj = res.data.data
            const { area, avatar, city, nickname, province } = obj
            // console.log(obj);

            // 数据回填
            $('avatar').src = avatar
            $('nickname').value = nickname

            // 把省的数据整体填入
            const resProvince = await axios.get('/api/province')
            $('province').innerHTML += resProvince.data.data.map(item => `<option value="${item}">${item}</option>`)
            $('province').value = province


            // 把市的数据整体填入
            const resCity = await axios.get(`/api/city?pname=${province}`)
            $('city').innerHTML += resCity.data.data.map(item => `<option value="${item}">${item}</option>`)
            $('city').value = city


            // 把地区的数据整体填入
            const resArea = await axios.get(`/api/area?pname=${province}&cname=${city}`)
            $('area').innerHTML += resArea.data.data.map(item => `<option value="${item}">${item}</option>`)
            $('area').value = area

        }
        getInfo()


        // 给省这个下拉框添加change事件
        $('province').addEventListener('change', async function () {
            // 获取最新选择的省
            const province = $('province').value
            // 发请求,得到对应的市
            const resCity = await axios.get(`/api/city?pname=${province}`)
            // console.log(resCity);
            // 添加(渲染)到页面
            $('city').innerHTML = resCity.data.data.map(item => `<option value="${item}">${item}</option>`)
            // 默认选择第一个市
            const city = resCity.data.data[0]
            $('city').value = city

            // 发请求,得到对应的地区
            const resArea = await axios.get(`/api/area?pname=${province}&cname=${city}`)
            // console.log(resArea);
            // 添加(渲染)到页面
            $('area').innerHTML = resArea.data.data.map(item => `<option value="${item}">${item}</option>`)
            $('area').value = resArea.data.data[0]
        })


        // 给市这个下拉框添加change事件
        $('city').addEventListener('change', async function () {
            // 获取最新选择的省
            const province = $('province').value
            // 拿到最新的市
            const city = $('city').value
            // 发请求,得到对应的市
            // console.log(city);

            // 发请求,得到对应的地区
            const resArea = await axios.get(`/api/area?pname=${province}&cname=${city}`)
            // console.log(resArea);
            // 添加(渲染)到页面
            $('area').innerHTML = resArea.data.data.map(item => `<option value="${item}">${item}</option>`)
            $('area').value = resArea.data.data[0]
        })


        // 修改图像

        // 给修改头像img注册点击事件
        $('avatar').addEventListener('click', function () {
            $('upload').click()
        })


        $('upload').addEventListener('change', async function (e) {
            let file = e.target.files[0]
            let fd = new FormData()
            fd.append('avatar', file)

            const portrait = await axios({
                url: '/api/file',
                method: 'POST',
                data: fd
            })
            console.log(portrait);

            $('avatar').src = portrait.data.data.url
        })


        // 保存按钮
        $('btnSave').addEventListener('click', async function (e) {
            // 阻止默认行为
            e.preventDefault()
            const nickname = $('nickname').value
            const province = $('province').value
            const city = $('city').value
            const area = $('area').value
            const avatar = $('avatar').src

            try {
                await axios.put('/api/settings', {
                    nickname,
                    province,
                    city,
                    area,
                    avatar
                })

                alert('YES')
            } catch (err) {
                alert('NO')
            }
        })
    </script>

任何需求的思路是:先标签后样式, 再数据铺设/绑定事件, 根据画面拆分需求按步骤实现, 前端准备好就调用接口

六.自测题Ajax

这里有10道Ajax选择题(祝你得100分): 异步编程和事件循环

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Moraxz/article/details/128008224

js的event loop(事件循环)_lioent的博客-爱代码爱编程

什么是事件循环 事件循环就是js在运行所有代码的执行顺序 事件循环 我们都知道,js有同步代码和异步代码,在一开始,js会执行所有的代码,同步的立即执行,异步的就放入task queue列表,在所有的同步代码执行完毕后

总结事件轮询机制,以及宏任务队列与微任务队列_esunr的博客-爱代码爱编程

1. 事件轮询(Event Loop) js实现异步的具体解决方案什么叫轮询? 2. 宏任务和微任务 概念宏任务微任务例题 EXP1: 在主线程上添加宏任务与微任务EXP2: 在微任务中创建微任务EXP

javascript:彻底理解同步、异步和事件循环(event loop)_普通网友的博客-爱代码爱编程

一. 单线程 我们常说“JavaScript是单线程的”。 所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。不妨叫它主线程。 但是实际上还存在其他的线程。例如:处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程(例如在Node.js中)等等。这些线程可能存在于JS引擎之

js 事件轮询(event loop) 任务队列 微任务(micro-task)宏任务(macro-task)_baobaosun3271的博客-爱代码爱编程

事件轮询(Event Loop) JavaScript的一大特点就是是单线程,所有任务都需要在主线程里排队等待执行。 而JavaScript里的任务又分为同步任务和异步任务两种,基于事件循环(Event Loop)机制执行任务。 同步任务作为首要任务会在主线程里执行,异步任务则被“发配”到由另一个线程管理的任务队列中等待处理。异步任务符合条件(比如a

javascript的事件队列(event queue)-爱代码爱编程

前言 在写代码的时候经常思考一个问题,到底是那个函数先执行,本身JavaScript是一门单线程的语言,意思就是按照顺序执行。但是加入一些setTimeout和promise的函数来又实现了异步操作,常常我会写一个setTimeout(fn,0),他会立即执行吗? 宏任务和微任务 首先我们先来看一段代码: <script>

浏览器事件队列及微任务和宏任务-爱代码爱编程

一、JS中的事件(任务)队列 Event Queue 浏览器从服务器获取到代码后,浏览器会开辟一个GUI渲染线程,GUI从上到下开始执行代码。 浏览器是多线程的,包含GUI渲染线程、HTTP网络请求线程(并发数6-7)、事件监听\定时器监听。但JS代码的运行是单线程的 console.log(1); setTimeout(() => { // 任

事件循环队列与宏任务和微任务-爱代码爱编程

说到事件循环队列, 就要知道怎么形成一个事件循环: 首先我们要知道, 我们的JavaScript是单线程的,( 所谓的单线程就是说, 事情要一件一件的做, 转换在代码上就是说代码是 一行一行的执行的 ),.大家都知道同步把,同步代码就是从上到下执行,前面的代码不执行完, 会阻塞后面代码的执行 . 但是说到同步就要说到异步 , 异步代码就不是一行一行从上到下

Ajax 异步编程-爱代码爱编程

Ajax 异步编程 1. 同步异步概述 1.1 同步 一个人同一时间只能做一件事情, 只有一件事情做完, 才能做另外一件事落实到代码中, 就是上一行代码执行完成后, 才能执行下一行代码, 即代码逐行执行1.2 异步 一个人一件事情做了一半, 转而去做其他事情, 当其他事情做完以后, 再回过头继续做之前未完成的事情落实到代码上, 就是异步代码虽然需要

任务队列之宏任务、微任务-爱代码爱编程

概念 在一个事件循环中,异步事件返回结果后会被放到一个任务队列中。然而,根据这个异步事件的类型,这个事件实际上会被对应的宏任务队列或者微任务队列中去。并且在当前执行栈为空的时候,主线程会 查看微任务队列是否有事件存在。如果不存在,那么再去宏任务队列中取出一个事件并把对应的回到加入当前执行栈;如果存在,则会依次执行队列中事件对应的回调,直到微任务队列为空,

js事件队列(event-loop)宏任务、微任务-爱代码爱编程

# 为什么要有事件循环呢? event loop顾名思义就是事件循环,为什么要有事件循环呢?因为V8是单线程的,即同一时间只能干一件事情,但是呢文件的读取,网络的IO处理是很缓慢的,并且是不确定的,如果同步等待它们响应,那么用户就起飞了。于是我们就把这个事件加入到一个 事件队列里(task),等到事件完成时,event loop再执行一个事件队列。  

事件队列、微任务与宏任务的理解和面试题_至尊绝伦的博客-爱代码爱编程

事件队列是一种数据结构,可以存放要执行的任务。它符合队列"先进先出"的特点。 事件循环中并非只维护着一个队列,事实上是有两个队列: 宏任务队列(macrotask queue): ajax、setTimeout、setInterval、DOM监听、UI Rendering等微任务队列(microtask queue): Promise的then回调、M

事件循环、宏任务、微任务_小白啥时候能进阶成功的博客-爱代码爱编程

1、为什么了解事件循环  可以判定使用什么函数去处理代码:例如,你需要在dom渲染之前做好逻辑处理,等待dom渲染完毕后,展示于页面,此时必用微任务方式处理;反之需要获取dom的操作就需要采用宏任务的相关代码去包裹处理函数,才不至于获取不到元素而报错!!!  2、宏任务和微任务 宏任务:JS宿主环境提供的API > script(整体代码)

js异步编程(一)事件循环与消息队列_前端~浅海鱼的博客-爱代码爱编程

一、同步模式和异步模式 1.js单线程: 最早js语言就是运行在浏览器端的语言,目的是为了实现页面上的动态交互。 实现页面交互的核心就是DOM操作,这就决定了它必须使用单线程模型,否则就会出现很复杂的线程同步问题 假设在

事件循环队列中的宏任务与微任务_vanora1111的博客-爱代码爱编程

目录 前言 总结 前言 事件循环中并非只维护着一个队列,事实上有两个队列: 宏任务队列(macrotask queue):ajax、setTimeout、setInterval、DOM监听、UI Rendering等。 微任务队列(microtask queue): Pomise的then回调、Mutation Observe

async和await概念 浏览器eventloop事件循环 以及一些遇到的相关面试题_小臂宰治的博客-爱代码爱编程

取代then函数, 来提取Promise的值 Promise链式调用 // 目标: 使用Promise的链式调用解决问题 // 前提: axios函数在原地返回的就是一个Promise对象 let pname = '' axios.get('http://ajax-api.itheima.net/api/province').then(res =>

宏任务和微任务_常见的宏任务和微任务-爱代码爱编程

宏任务微任务 宏任务和微任务基本概念介绍同步异步事件循环机制 常见的微任务和宏任务举例说明代码输出题1代码输出题2代码输出题3 宏任务和微任务 基本概念介绍 同步异步 在了

每日必记五题(第二天)-爱代码爱编程

1.Promise.all(),一个失败后,其他的还返回吗? 答:不会返回,promise.all()失败的时候只返回最先被reject失败状态的那个实例对象的值 2.Promise.all()、Promise