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知识库]异步编程笔记

异步编程

目录

一.EventLoop

1.JavaScript 是单线程的语言

2.同步任务和异步任务

3.EventLoop执行过程

二.Promise

三.async与await

四.宏任务和微任务


一.EventLoop

1.JavaScript 是单线程的语言

基本概念

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

执行流程图

单线程执行任务队列的问题: 如果前一个任务非常耗时,则后续的任务就不得不一直等待,从而导致程序假死的问题。

2.同步任务和异步任务

为了防止某个耗时任务导致程序假死的问题,JavaScript 把待执行的任务分为了两类:

  • 同步任务(synchronous)

    • 又叫做非耗时任务,指的是在主线程上排队执行的那些任务

    • 只有前一个任务执行完毕,才能执行后一个任务

  • 异步任务(asynchronous)

    • 又叫做耗时任务,异步任务由JavaScript 委托给宿主环境(浏览器 nodejs)进行执行

    • 当异步任务执行完成后,会通知 JavaScript 主线程执行异步任务的回调函数

同步代码:从上->下逐行执行,下一行必须等待上一行的结果才往下执行

异步代码:使用回调函数来接收结果

注意:setTimeout本身是同步的,但是里面的回调函数是异步执行的

    <script>
        // 同步代码
        // 概念: 从上到下逐行执行, 下一行必须等待上一行的结果才行
        console.log(1);
        if (true){
            console.log(2);
        }
        // 绑定是同步的, 事件处理函数会异步执行
        document.addEventListener('click', () => {
            console.log(3);
        })
        console.log(4);
        setTimeout(() => {
            console.log(5);
        }, 0)
        console.log(6);
        for (let i = 0; i < 100; i++) {
            console.log("for循环");
        }
        console.log(7);

        // 异步代码:
        // setTimeout(回调函数), setInterval(回调函数), ajax网络请求(回调函数), 事件处理函数(回调函数)
        // 框架: this.$nextTick() -> Promise (回调函数)
    </script>

?

3.EventLoop执行过程

  • 同步任务由 JavaScript 主线程次序执行

  • 异步任务委托给宿主环境执行

  • 已完成的异步任务对应的回调函数,会被加入到任务队列中等待执行

  • JavaScript 主线程的执行栈被清空后,会读取任务队列中的回调函数,次序执行

  • JavaScript 主线程不断重复上面的第 4 步

执行栈:用来执行代码(

Web APIS:异步代码(js代码运行在浏览器环境中,调用浏览器中的功能来实现异步中回调的执行)

任务队列:任务队列中存放的都是异步任务中的回调函数(把异步任务中要执行的函数体放在任务队列中等着被执行栈执行)

注意

代码在执行之前先进行函数预解析、变量预解析,解析完成后才开始执行代码

所有的异步任务只有在执行栈空闲(即主线程 | 同步代码执行完成后)的时候才会执行

JavaScript 主线程从“任务队列”中读取异步任务的回调函数,放到执行栈中依次执行。这个过程是循环不断的,所以整个的这种运行机制又称为 EventLoop(事件循环)

总结:主执行栈从任务队列中拿任务执行,这样的循环过程叫 EventLoop--展现异步代码如何执行的(事件循环)

二.Promise

概念: 关联(管理-包含)异步任务的对象, 将来拿到异步任务成功/失败的结果

 <script>
        console.log(1)
        // 复习Promise
        // 概念: 关联(管理-包含)异步任务的对象, 将来拿到异步任务成功/失败的结果
        // 使用:
        // new Promise()被实例化了, 函数体里的代码立刻执行(同步)
        let p = new Promise((resolve, reject) => {
            console.log(2)
            // 内置传参数:
            // resolve被调用 -> 管理任务成功 -> then()里回调函数执行
            // reject() => 管理任务失败 -> catch()里回调函数执行
            resolve('成功')
            console.log(3);
        })
        console.log(4);
        // p.then().catch()绑定了监听成功/失败结果的函数-并不会马上执行("resolve异步的")
        p.then(res => {
            console.log(5);
            console.log(res)
        }).catch(err => {
            console.log(6);
            console.log(err)
        })
        console.log(7);
    </script>

?

三.async与await

基本概念

async await号称异步的终极解决方案,async await之后再无回调

async/await 是 ES8(ECMAScript 2017)引入的新语法,用来简化 Promise 异步操作。在 async/await 出 现之前,开发者只能通过链式.then() 的方式处理 Promise 异步操作。

  • .then方式的优点:

    • 解决了回调地狱的问题

  • .then方式的缺点

    • 代码冗余、阅读性差、不易理解

基本使用

async 和 await 是一对关键字

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

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

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

  2. await 要用在 async 函数中

  3. await 后面一般会跟一个promise对象, await会阻塞async函数的执行,直到等到 promise成功的结果(resolve的结果)

 <script>
        // async函数+await 取代了.then() 
        // new Promise()会立刻执行函数体里面一切代码
        // resolve() 异步的
        // await (代码会在async函数内, 等待停止) -> 右结合(先执行await右边的代码)
        // 如果等待, 也还会把async外的代码继续执行 (如果有同步代码接着跑)
        console.log(1)
        function createPromiseObj() {
            console.log(2);
            return new Promise((resolve, reject) => {
                console.log(3)
                resolve('成功')
                console.log(4);
            })
            console.log(5);
        }
        console.log(6);
        testOne()
        console.log(7);
        async function testOne() {
            console.log(8);
            const res = await createPromiseObj() 
            console.log(res);
            console.log(9);
        }
        console.log(10);
 </script>

?

注意:只有await往后的才是异步代码

1. async和await是一对关键字,必须成对出现
2. async用于修饰一个函数,代表该函数是一个异步函数
3. await用于等待一个值,通常是一个promise对象
4. await后面是一个普通值,那会直接返回该值本身,如果await后面是一个promise,会返回promise成功的结果

await遇到基础值的情况:即await后面不是Promise对象

若await操作符后的表达式的值不是一个Promise,则返回该值本身,若该值不是一个Promise,阿瓦提会把该值转换为已正常处理的Promise(不是Promise,会转成Promise,还是会被当成异步任务放到任务队列中等待),然后等到其处理结果

    <script>
        // await 后面表达式 : promise对象、 具体值
        // await遇到具体值, 会把它转换成Promise成功的结果 (Promise.resolve(2))
        // Promise.resolve(2) -> Promise对象里调用resolve(2)
        console.log(1)
        async function fn() {
            console.log(4)
            const res = await 2
            // 等同于
            // const res = await Promise.resolve(2)
            console.log(res)
        }
        fn()
        console.log(3)
    </script>

运行结果如下:

四.宏任务和微任务

基本概念:

JavaScript 把任务队列分为宏任务队列微任务队列

  • 宏任务(macrotask)

    • 整个script标签

    • 事件绑定

    • 异步 Ajax 请求

    • 定时器:setTimeout、setInterval

    • 文件操作

    • 其它宏任务

  • 微任务(microtask)(微任务的宿主不是浏览器,是JS引擎)

    • Promise(执行resolve()会把回调函数.then()会把其返回的成功结果放在任务队列中)

    • process.nextTick

注意:微任务会排在宏任务之前执行

流程图

 <script>
        console.log(1);
        setTimeout(() => { // 宏任务
            console.log(2);
        }, 0)
        console.log(3);
        function pro(){
            return new Promise((resolve, reject) => {
                console.log(4);
                resolve('成功') // 微任务(宿主->JS引擎)
                console.log(5);
            })
        }
        async function fn(){
            console.log(6);
            const res = await pro()
            console.log(res);
        }
        fn()
        console.log(7);
        // 微任务会排列在宏任务之前
  </script>

?练习题1:

  <script>
        console.log(1)
        // 只要看到了加了时间, 那么一定是等时间满足了, 才会加入到任务队列中
        setTimeout(function () {
            console.log(2)
        }, 0)
        const p = new Promise((resolve, reject) => {
            resolve(1000)
        })
        p.then(data => {
            console.log(data)
        })
        console.log(3)
  </script>

?

?练习题2:

    <script>
        console.log(1)
        setTimeout(function () {
            console.log(2)
            new Promise(function (resolve) {
                console.log(3)
                resolve()
            }).then(function () {
                console.log(4)
            })
        })
        new Promise(function (resolve) {
            console.log(5)
            resolve()
        }).then(function () {
            console.log(6)
        })
        setTimeout(function () {
            console.log(7)
            new Promise(function (resolve) {
                console.log(8)
                resolve()
            }).then(function () {
                console.log(9)
            })
        })
        console.log(10)
    </script>
    <script>
        // 0号宏任务 <script>里面的所有同步代码
        // 宏任务执行完毕, 清空微任务队列里所有微任务, 再执行下一个宏任务
    </script>

?

练习题3:

    <script>
        console.log(1)
        // 只要看到了加了时间, 那么一定是等时间满足了, 才会加入到任务队列
        setTimeout(function () {
            console.log(2)
        }, 0)
        // new Promise()会立刻执行函数体里面一切代码
        const p = new Promise((resolve, reject) => {
            console.log(3)
            resolve(1000) // 标记为成功,指定.then(); reject()表示为失败,执行catch()
            console.log(4)
        })
        p.then(data => {
            console.log(data)
        })
        console.log(5)
    </script>

?

?练习题4:

resolve()不会阻塞代码往下执行
await会阻塞代码往下执行

微任务同时有多个时,后来者居上(先执行

    <script>
        // 微任务同时有多个, 往前面插入排队
        new Promise((resolve, reject) => {
            resolve(1) // 状态凝结 (Promise对象已经有了结果->后面的resolve和reject都没用)
            resolve(100) 
            new Promise((resolve, reject) => {
                resolve(2)
            }).then(data => {
                console.log(data)
            })
        }).then(data => {
            console.log(data)
        })
        console.log(3)
    </script>

?

?练习题5:

    <script>
        setTimeout(() => {
            console.log(1)
        }, 0)
        new Promise((resolve, reject) => {
            console.log(2)
            resolve('p1')

            new Promise((resolve, reject) => {
                console.log(3)
                setTimeout(() => {
                    resolve('setTimeout2')
                    console.log(4)
                }, 0)
                resolve('p2')
            }).then(data => {
                console.log(data)
            })

            setTimeout(() => {
                resolve('setTimeout1')
                console.log(5)
            }, 0)
        }).then(data => {
            console.log(data)
        })
        console.log(6)
    </script>

?

总结

resolve会调用.then()方法,放在异步任务队列中的微任务队列中
resolve不会阻塞后面代码的执行

状态凝结Promise对象已经有了结果,后面的resolvereject不执行

微任务同时有多个时,后来者居上(先执行

定时器
相同时间,按放在宏任务队列中的先后顺序执行
不同时间,时间短的在前先执行

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-27 12:44:50  更:2021-10-27 12:46:44 
 
开发: 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/12 1:00:30-

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