8-js高级-6(promise)

news2024/11/26 13:31:23

一 Promise 的理解和使用

1 Promise 是什么?

理解

抽象表达:

  • Promise 是一门新的技术(ES6 规范)
  • Promise 是 JS 中进行异步编程的新解决方案 (备注:旧方案是单纯使用回调函数)

具体表达:

  • 从语法上来说: Promise 是一个构造函数
  • 从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/ 失败的结果值

promise 的状态改变

  1. pending 变为 resolved
  2. pending 变为 rejected

**说明: **

只有这 2 种, 且一个 promise 对象只能改变一次

无论变为成功还是失败, 都会有一个结果数据

成功的结果数据一般称为 value, 失败的结果数据一般称为 reason

promise 的基本流程

在这里插入图片描述

promise 的基本使用

  • 使用 1: 基本编码流程
  <script>
        // 1) 创建 promise 对象(pending 状态), 指定执行器函数
        const p = new Promise((resolve, reject) => {
            // 2) 在执行器函数中启动异步任务
            setTimeout(() => {
                const time = Date.now();
                // 3) 根据结果做不同处理
                if (time % 2 == 1) {
                    // 3.1) 如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状态
                    resolve("成功的值" + time);
                } else {
                    // 3.2) 如果失败了, 调用 reject(), 指定失败的 reason, 变为rejected 状态
                    reject("失败的值" + time);
                }
            }, 2000);
        });

        // 4) 能 promise 指定成功或失败的回调函数来获取成功的 vlaue 或失败的 reason
        p.then(
            // 成功的回调函数 onResolved, 得到成功的 vlaue
            value => console.log('成功的 value: ', value),
            // 失败的回调函数 onRejected, 得到失败的 reason
            reason => console.log('失败的 reason: ', reason)
        );
      
    </script>
  • 使用 2: 使用 promise 封装基于定时器的异步
    <script>

        function doDelay(time) {
            return new Promise((resolve, reject) => {

                setTimeout(() => {
                    const now = Date.now();
                    if (now % 2 == 1) {
                        resolve("成功的值" + now);
                    } else {
                        reject("失败的值" + now);
                    }
                }, time);
            });
        }

        const promise = doDelay(2000);
        promise.then(
            value => console.log('成功的 value: ', value),
            reason => console.log('失败的 reason: ', reason)
        );


    </script>
  • 使用 3: 使用 promise 封装 ajax 异步请求
    <script>

        //可复用的发 ajax 请求的函数: xhr + promise
        function promiseAjax(url) {
            return new Promise((resolve, reject) => {
                const xhr = new XMLHttpRequest()
                xhr.onreadystatechange = () => {
                    if (xhr.readyState !== 4) return
                    const { status, response } = xhr
                    // 请求成功, 调用 resolve(value)
                    if (status >= 200 && status < 300) {
                        resolve(JSON.parse(response))
                    } else { // 请求失败, 调用 reject(reason)
                        reject(new Error('请求失败: status: ' + status))
                    }
                }
                xhr.open("GET", url)
                xhr.send()
            })
        }
        promiseAjax('http://152.136.185.210:7878/api/hy66/home/data?type=pop&page=1')
            .then(
                data => {
                    console.log('显示成功数据', data)
                },
                error => {
                    alert(error.message)
                }
            )

    </script>

2 为什么要用 Promise?

指定回调函数的方式更加灵活

  1. 旧的: 必须在启动异步任务前指定

  2. promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函 数(甚至可以在异步任务结束后指定/多个)

支持链式调用, 可以解决回调地狱问题

  1. 什么是回调地狱?

    回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件

  2. 回调地狱的缺点?

    不便于阅读 不便于异常处理

  3. 解决方案?

    promise 链式调用

  4. 终极解决方案?

    async/await

    <script>
        // 成功的回调函数
        function successCallback(result) {
            console.log("声音文件创建成功: " + result);
        }
        // 失败的回调函数
        function failureCallback(error) {
            console.log("声音文件创建失败: " + error);
        }
        /* 1.1 使用纯回调函数 */
        createAudioFileAsync(audioSettings, successCallback, failureCallback)

        /* 1.2. 使用 Promise */
        const promise = createAudioFileAsync(audioSettings);
        setTimeout(() => {
            promise.then(successCallback, failureCallback);
        }, 3000);

        /*
        2.1. 回调地狱
        */
        doSomething(function (result) {
            doSomethingElse(result, function (newResult) {
                doThirdThing(newResult, function (finalResult) {
                    console.log('Got the final result: ' + finalResult)
                }, failureCallback)
            }, failureCallback)
        }, failureCallback)
        /*
        2.2. 使用 promise 的链式调用解决回调地狱
        */
        doSomething().then(function (result) {
            return doSomethingElse(result)
        }).then(function (newResult) {
            return doThirdThing(newResult)
        }).then(function (finalResult) {
            console.log('Got the final result: ' + finalResult)
        }).catch(failureCallback)
        /*
        2.3. async/await: 回调地狱的终极解决方案
        */
        async function request() {
            try {
                const result = await doSomething()
                const newResult = await doSomethingElse(result)
                const finalResult = await doThirdThing(newResult)
                console.log('Got the final result: ' + finalResult)
            } catch (error) {
                failureCallback(error)
            }
        }

    </script>

如何使用 Promise?

API

  1. Promise 构造函数: Promise (excutor) {}
    • executor 函数: 执行器 (resolve, reject) => {}
    • resolve 函数: 内部定义成功时我们调用的函数 value => {}
    • reject 函数: 内部定义失败时我们调用的函数 reason => {}
    • 说明: executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行
  2. Promise.prototype.then 方法: (onResolved, onRejected) => {}
    • onResolved 函数: 成功的回调函数 (value) => {}
    • onRejected 函数: 失败的回调函数 (reason) => {}
    • 说明: 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调
    • 返回一个新的 promise 对象
  3. Promise.prototype.catch 方法: (onRejected) => {}
    • onRejected 函数: 失败的回调函数 (reason) => {}
    • 说明: then()的语法糖, 相当于: then(undefined, onRejected)
  4. Promise.resolve 方法: (value) => {}
    • value: 成功的数据或 promise 对象
    • 说明: 返回一个成功/失败的 promise 对象
    • 说明: 当value为失败的promise对象时则返回一个失败的promise
  5. Promise.reject 方法: (reason) => {}
    • reason: 失败的原因
    • 说明: 返回一个失败的 promise 对象
  6. Promise.all 方法: (promises) => {}
    • promises: 包含 n 个 promise 的数组
    • 说明: 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就 直接失败
  7. Promise.race 方法: (promises) => {}
    • promises: 包含 n 个 promise 的数组
    • 说明: 返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态

promise 的几个关键问题

  1. 如何改变 promise 的状态?
    • resolve(value): 如果当前是 pending 就会变为 resolved
    • reject(reason): 如果当前是 pending 就会变为 rejected
    • 抛出异常: 如果当前是 pending 就会变为 rejected
  2. 一个 promise 指定多个成功/失败回调函数, 都会调用吗?
    • 当 promise 改变为对应状态时都会调用
  3. 改变 promise 状态和指定回调函数谁先谁后?
    • 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
    • 如何先改状态再指定回调?
      • 在执行器中直接调用 resolve()/reject()
      • 延迟更长时间才调用 then()
    • 什么时候才能得到数据?
      • 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
      • 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
  4. promise.then()返回的新 promise 的结果状态由什么决定?
    • 简单表达: 由 then()指定的回调函数执行的结果决定
    • 详细表达:
      • 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
      • 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
      • 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
  5. promise 如何串连多个操作任务?
    • promise 的 then()返回一个新的 promise, 可以开成 then()的链式调用
    • 通过 then 的链式调用串连多个同步/异步任务
  6. promise 异常传透?
    • 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,
    • 前面任何操作出了异常, 都会传到最后失败的回调中处理
  7. 中断 promise 链?
    • 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
    • 办法: 在回调函数中返回一个 pendding 状态的 promise 对象

二 async 与 await

定义

async 是异步的意思,await则可以理解为 async wait。所以可以理解async就是用来声明一个异步方法,而 await是用来等待异步方法执行

async作为一个关键字放在函数前面,表示该函数是一个异步函数,异步函数意味着该函数的执行不会阻塞后面代码的执行;而 await 用于等待一个异步方法执行完成;

async/await的作用就是使异步操作以同步的方式去执行

1 关于async

async的用法,语法很简单,在函数前面加上async关键字,表示函数是异步的。

 async function timeout() {
     return 'hello world!'
 }

只有一个作用,他的调用会返回一个promise对象。

那怎么调用呢?async 函数也是函数,平时我们怎么使用函数就怎么使用它,直接加括号调用就可以了,为了表示它没有阻塞它后面代码的执行,我们在async 函数调用之后加一句console.log;

 async function timeout() {
     return 'hello world!'
 }
 timeout()
 console.log('我虽然在后面,但是先执行')

打印结果:

在这里插入图片描述

发现 timeout() 函数虽然调用了,但是没打印 hello world!; 先不要着急, 看一看timeout() 返回了什么? 把上面的 timeout() 语句改为console.log(timeout())

打印结果:

在这里插入图片描述

原来async 函数返回的是一个promise 对象,并且Promise还有state和result,如果async函数中有返回值,当调用该函数时,内部会调用Promise.resolve()方法把它转化成一个promise对象作为返回,但如果timeout函数内部抛出错误呢? 那么就会调用Promise.reject() 返回一个promise 对象

async function timeout() {
    throw new Error('rejected');
}
console.log(timeout());

就会调用Promise.reject() 返回一个promise 对象

在这里插入图片描述

那么要想获取到async 函数的执行结果,就要调用promise的then 或 catch 来给它注册回调函数

继续修改代码

  	async function timeout() {
      return 'hello world!'
    }

    timeout().then(val => {
      console.log(val)
    })

    console.log('我虽然在后面,但是先执行')

在这里插入图片描述

我们获取到了"hello world!', 同时timeout的执行也没有阻塞后面代码的执行,和我们刚才说的一致。

如果async 函数执行完,返回的promise 没有注册回调函数,比如函数内部做了一次for 循环,你会发现函数的调用,就是执行了函数体,和普通函数没有区别,唯一的区别就是函数执行完会返回一个promise 对象

   async function timeout () {
      for (let index = 0; index < 3; index++) {
        console.log('async', +index)
      }
    }
    console.log(timeout())
    console.log('outer')

在这里插入图片描述

另外,async函数返回一个promise对象,下面两种方法是等效的

// 方法1
function f() {
    return Promise.resolve('TEST');
}
// asyncF is equivalent to f!

// 方法2
async function asyncF() {
    return 'TEST';
}

2 关于await

await 到底在等啥?

async 关键字差不多了,最重要的就是async函数的执行会返回promise对象,并且把内部的值进行promise的封装。如果promise对象通过then或catch方法又注册了回调函数,async函数执行完以后,注册的回调函数就会放到异步队列中,等待执行。

如果只是async,和promise差不多,但有了await就不一样了,await关键字只能放到async函数里面,await是等待的意思,那么它等待什么呢?它后面跟着什么呢?其实await不仅仅用于等Promise对象,还可以等任意表达式,所以await后面实际是可以接普通函数调用或者直接量的,不过我们更多的是放一个返回promise 对象的表达式。他等待的是promise对象执行完毕,并返回结果。

//所以下面这个示例完全可以正确运行
    function getSomething () {
      return 'something'
    }
    async function testAsync () {
      return Promise.resolve('hello async')
    }
    async function test () {
      const v1 = await getSomething()
      const v2 = await testAsync()
      console.log(v1, v2)
    }
    test()

await 等到了要等的,然后呢?

await 等到了它要等的东西,一个 Promise 对象,或者其它值,然后呢?

  1. 如果它等到的不是一个Promise对象,那么await表达式的运算结果就是它等到的东西。
  2. 如果它等到的是一个Promise对象,await就忙起来了,它会阻塞函数后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运算结果。

async/await 帮我们干了啥?

做个简单的比较
现在举例,用 setTimeout 模拟耗时的异步操作,先来看看不用 async/await 会怎么写

function takeLongTime () {
      return new Promise(resolve => {
        setTimeout(() =>
          resolve('long_time_value'), 1000
        )
      })
    }
takeLongTime().then(val => {
   console.log(val, 'val')
})

如果改用 async/await 呢,会是这样

    function takeLongTime () {
      return new Promise(resolve => {
        setTimeout(() =>
          resolve('long_time_value'), 1000
        )
      })
    }
     async function test () {
      let v = await takeLongTime()
      console.log(v, 'v')
    }
    test()

眼尖的已经发现 takeLongTime () 没有申明为async。实际上takeLongTime () 本身就返回Promise对象,加不加async结果都一样。

await 优势在于处理 then 链,使代码看起来像同步代码一样,下面是实例应用

现在写一个函数,让它返回promise 对象,该函数的作用是2s 之后让数值乘以2

// 2s 之后返回双倍的值
function doubleAfter2seconds (num) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(num * 2)
        }, 2000)
      })
    }

现在再写一个async 函数,从而可以使用await 关键字, await 后面放置的就是返回promise对象的一个表达式,所以它后面可以写上 doubleAfter2seconds 函数的调用

async function testResult() {
    let result = await doubleAfter2seconds(30);
    console.log(result); //2s后打印60
}
testResult();

代码的执行过程

调用testResult 函数,它里面遇到了await, await 表示等待,代码就暂停到这里,不再向下执行了,它等待后面的promise对象执行完毕,然后拿到promise resolve 的值并进行返回,返回值拿到之后,它继续向下执行。具体到 我们的代码, 遇到await 之后,代码就暂停执行了, 等待doubleAfter2seconds(30) 执行完毕,doubleAfter2seconds(30) 返回的promise 开始执行,2秒 之后,promise resolve 了, 并返回了值为60, 这时await 才拿到返回值60, 然后赋值给result, 暂停结束,代码继续执行,执行 console.log语句。

就这一个函数,我们可能看不出async/await 的作用,如果我们要计算3个数的值,然后把得到的值进行输出呢?

async function testResult() {
    let first = await doubleAfter2seconds(30);
    let second = await doubleAfter2seconds(50);
    let third = await doubleAfter2seconds(30);
    console.log(first + second + third);
}
testResult()

6秒后,控制台输出220, 我们可以看到,写异步代码就像写同步代码一样了,再也没有回调地域了。

这里强调一下,当js引擎在等待promise.resolve的时候,他并没有真正的暂停工作,它可以处理其他的一些事情,如果我们在testResult函数后面继续执行其他代码,比如console.log一下,会发现console.log代码先执行。

async function testResult() {
    let first = await doubleAfter2seconds(30);
    let second = await doubleAfter2seconds(50);
    let third = await doubleAfter2seconds(30);
    console.log(first + second + third);
}
testResult()
console.log('我先执行!!!')

先输出 “我先执行!!!”,6s后输出计算结果。

在这里插入图片描述

3 举例

当遇到 await 时,会阻塞函数内部处于它后面的代码(而非整段代码),去执行该函数外部的同步代码;当外部的同步代码执行完毕,再回到该函数执行剩余的代码。并且当 await 执行完毕之后,会优先处理微任务队列的代码。

 <script>
        async function fn1() {
            console.log(1)
            const value = await fn2() // fn2进入微任务队列等待执行
            console.log(value)
            console.log(2) // 阻塞
        }
        async function fn2() {
            console.log('fn2')
            return 666;
        }
        fn1()
        console.log(3)
    </script>

    // 结果:1 fn2 3 666 2
    // 痛点:
    // 执行fn2()后返回一个成功状态且值为666的promise,该promise的then的回调进入微任务队列等待执行
    // await 会阻塞它下面的代码,先执行 async 外面的同步代码
    // 同步代码执行完后,执行异步任务(当前为微任务队列中得promise的then的回调)
    // 释放了async函数中的await的阻塞,使得其后的代码得到执行

4 总结:

  1. async 函数
    1)函数的返回值为Promise对象
    2)Promise对象的结果由async函数执行的返回值决定
  2. await 表达式
    1)正常情况下,await右侧的表达式一般为 promise对象 , 但也可以是其它的值
    2)如果表达式是promise对象,await就忙起来了,它会阻塞函数后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运算结果。
    3)如果表达式是其它值, 直接将此值作为await的返回值
  3. asyncawait基于promise的。使用async的函数将会始终返回一个 promise 对象。这一点很重要,要记住,可能是你遇到容易犯错的地方。
  4. 在使用await的时候我们只是暂停了函数,而非整段代码。这里经常会是容易犯错的地方。
  5. async和await是非阻塞的
  6. 仍然可以使用 Promise,例如Promise.all(p1, p2, p3).,接受一个数组作为参数,p1、p2、p3 都是 Promise 实例,如果不是,就会先调用 Promise .resolve方法,将参数转为 Promise 实例,再进一步处理。只要 p1、p2、p3 之中有一个被 rejected,整个状态就变成 rejected。
  7. 注意
    1)await必须写在async函数中, 但async函数中可以没有await
    2)如果await的promise失败了, 就会抛出异常, 需要通过try…catch来捕获处理

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

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

相关文章

vue3 实现排序按钮

需求背景解决效果index.vue 需求背景 需要实现一个复用性&#xff0c;是提供表单顺倒排序的按钮 解决效果 index.vue <!--/*** author: liuk* date: 2023/7/25* describe: 排序按钮*/--> <template><div class"sort-fn"><span :class"[…

记一次完整体系的攻防演练

准备工作&#xff1a; 1&#xff0c;在客户的内网环境部署一个Windows7系统&#xff0c;在这个系统上把finecms这个应用部署上去。把finecms安装之后&#xff0c;和客户沟通&#xff0c;把这个应用的地址映射到公网上去。 2&#xff0c;其次&#xff0c;没有条件的话&#xff0…

蓝桥杯上岸必背!!!(第七期 最短路算法)

第七期&#xff1a;最短路算法&#x1f525; &#x1f525; &#x1f525; 蓝桥杯热门考点模板总结来啦✨ 你绝绝绝绝绝绝对不能错过的常考最短路算法模板 &#x1f4a5; ❗️ ❗️ ❗️ 大家好 我是寸铁✨ 还没背熟模板的伙伴们背起来 &#x1f4aa; &#x1f4aa; &…

SpringBoot整合JavaMail

SpringBoot整合JavaMail 简单使用-发送简单邮件 介绍协议 导入坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>添加配置 spring:mail:host: smtp.qq.co…

JVM系统优化实践(23):GC生产环境案例(6)

您好&#xff0c;这里是「码农镖局」CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 在互联网大厂中&#xff0c;对每天亿级流量的日志进行清洗、整理是非常常见的工作。在某个系统中&#xff0c;需要对用户的访问日志做脱敏处理&#xff0c;也就是清洗掉姓名…

day41-Verify Account Ui(短信验证码小格子输入效果)

50 天学习 50 个项目 - HTMLCSS and JavaScript day41-Verify Account Ui&#xff08;短信验证码小格子输入效果&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name&qu…

Shell脚本实战——对MySQL进行分库分表备份

一、查看当前数据库以及数据表 如何除去Datebase标题字样以及系统自带的数据库呢&#xff1f;可以使用以下命令 mysql -uroot -p#BenJM123 -e show databases -N | egrep -v "information_schema|mysql|performance_schema|sys"剩下的两个就是用户自己创建的表啦&am…

分享一个JSON插件

文章目录 知识回顾使用方法 知识回顾 看官们&#xff0c;最近在使用Flutter做网络相关的操作&#xff0c;主要是Http请求操作&#xff0c;请求结果基本上都是JSON格式&#xff0c;因此需要把JSON格式转换成Dart语法的数据模型。如果手动编写的话会占用时间而且容易出错。因此&…

UCDOS和WPS推动计算机领域的汉字化发展,中文编程该谁力扛大旗?

你还记得UCDOS吗&#xff1f; 从DOS时代过来的人&#xff0c;还知道UCDOS的&#xff0c;现在可能已经是中年人了&#xff01; 当时&#xff0c;鲍岳桥的UCDOS可以称得上是中国的国产操作系统。 在Windows还没来得及进入中国市场时&#xff0c;UCDOS可以说是走向了巅峰时刻&a…

【分库分表】分库分表常见问题和解决方案

文章目录 前言MySQL出现的性能问题Mysql常见的优化手段大数据表优化方案详解分库分表垂直拆分单库垂直分表多库垂直分表 水平拆分单库水平分表多库水平分表常见的水平分表策略哈希取模分片hash取模的问题一致性hash算法按照范围分片 分库分表实战根据uid进行水平分表如何实现全…

lambda表达式的进阶过程

文章目录 什么是Lambda表达式简述Lambda表达式的优点语法格式 函数式接口定义常见的函数式接口汇总 Lambda的演化过程lambda表达式简化 总结 什么是Lambda表达式 简述 Lambda表达式是JAVA8中提供的一种新的特性&#xff0c;是一个匿名函数方法。可以把Lambda表达式理解为一段…

关于uniapp中的日历组件uni-calendar中的小红点

关于uniapp中的日历组件uni-calendar中的小红点 如果你使用过uni-calendar组件&#xff0c;可能你觉得这个小红点有点碍眼&#xff0c;但是官方给定的日历组件uni-calendar中如果你想要在某一天上添加一些信息例如:价格&#xff0c;签到&#xff0c;打卡之类&#xff0c;只要标…

【PWN · ret2text | 伪rand()】[HDCTF 2023]pwnner

伪随机数以及ctypes库的初步接触 目录 前言 一、题目 二、解题思路 三、exp 总结 前言 一道简单的ret2text&#xff0c;加上一些伪随机的知识&#xff0c;对于本蒟蒻萌新来说&#xff0c;比较新&#xff0c;值得记录。 一、题目 栈溢出保护、PIE保护都没有开。反汇编后…

servlet银行储蓄管理系统java存取转账交易 jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 servlet银行储蓄管理系统 系统有1权限&#xff1a;管…

python与深度学习(四):ANN和fashion_mnist二

目录 1. 说明2. fashion_mnist的ANN模型测试2.1 导入相关库2.2 加载数据和模型2.3 设置保存图片的路径2.4 加载图片2.5 图片预处理2.6 对图片进行预测2.7 显示图片 3. 完整代码和显示结果4. 多张图片进行测试的完整代码以及结果 1. 说明 本篇文章是对上篇文章训练的模型进行测…

Guitar Pro有没有免费的?

Guitar Pro是一款功能强大的吉他谱编辑软件&#xff0c;它为音乐创作者和乐手提供了极大的便利。但是&#xff0c;许多人对于Guitar Pro是否有免费版本&#xff0c;问题存在疑虑。下面我们就来详细介绍Guitar Pro有没有免费的内容吧&#xff01; 一、Guitar Pro有没有免费的 …

音视频——视频流H264编码格式

1 H264介绍 我们了解了什么是宏快&#xff0c;宏快作为压缩视频的最小的一部分&#xff0c;需要被组织&#xff0c;然后在网络之间做相互传输。 H264更深层次 —》宏块 太浅了 ​ 如果单纯的用宏快来发送数据是杂乱无章的&#xff0c;就好像在没有集装箱 出现之前&#xff0c;…

MultipartFile类型接收上传文件报出的UncheckedIOException以及删除tomcat临时文件失败源码探索

1、描述异常背景&#xff1a; 因为需要分析数据&#xff0c;待处理excel文件的数据行数太大&#xff0c;手动太累&#xff0c;花半小时写了一个定制的数据入库工具&#xff0c;改成了通用的&#xff0c;整个项目中的万级别数据都在工具上分析&#xff0c;写SQL进行分析&#x…

Rust vs Go:常用语法对比(十)

题图来自 Rust vs. Golang: Which One is Better?[1] 182. Quine program Output the source of the program. 输出程序的源代码 package mainimport "fmt"func main() { fmt.Printf("%s%c%s%c\n", s, 0x60, s, 0x60)}var s package mainimport "fm…

【C语言】嵌入式C语言项目管理利器:深入理解Makefile的应用与实践

目录 一、makedile的概述 1、案例引入 2、makefile 3、Makefile优点 二、makefile的语法规则 1、语法规则 2、简单实战 三、makefile的变量 1、自定义变量 2、系统环境变量 3、预定义变量 4、高级makefile 一、makedile的概述 1、案例引入 gcc a.c b.c c.c ‐o …