async和await用法理解和快速上手 , 同步任务和异步任务顺序安排和轻松理解 , js代码执行顺序表面知道

news2025/7/27 4:21:59

学习关键语句 :
async , await 用法
await 怎么使用
同步任务和异步任务
微任务和宏任务
js中代码执行顺序

写在前面

虽然说 async 和 await 是 Promise 的语法糖 , 但是用惯了Promise 的人(我) , 还真不能超快速使用上这个语法糖 , 所以赶紧写一篇文章出来让各位了解了解这个到底怎么用在我的项目中呢 , 毕竟大家都是想用在项目里的 , 而不是说简单的学习一下语法 难道只有我看了语法介绍还是不会用嘛

同时 这一部分和异步任务有很大的关系 , 因为一般 await 我们是在发起请求时使用的 , 所有我们同样也会看看 js 中的同步任务和异步任务

而且我们从异步任务开始会更好的理解了 await 的用法

而异步任务需要从同步任务开始

这篇文章的目的就是希望用最简单的话来说明白上面这一些东东

警告 ! 本文可能带有知识误导 , 得出的结论相不相信取决于自己 , 作者说.

开始

同步任务和异步任务

  1. 同步任务

低情商 : 不会吧 , 不会真有人来看同步任务是啥吧 ?

低情商解答 : 上一行代码不执行完下一行代码就不开始执行 , 这就是同步 , 而执行就是任务

高情商 : 兄弟们又来复习啦 , 温故而知新啊

高情商解答 : JavaScript 是一门单线程语言 , 这意味着对于你写的 js 代码 , 他的执行顺序必然是从上往下一行一行执行的 , 一旦哪行出错了 , 那整个程序都会停止运行 , 所以一行一行做任务我们称之为同步任务

  1. 异步任务

异步任务简单来说 , 就是他不是同步任务

啊这是在说 , 结合上面同步任务的意思 , 异步任务就不会一行一行的执行 , 他超脱了原本的代码执行顺序 , 异步任务有自己执行的时候 , 这个一会儿再看什么时候执行

异步任务分为两种 , 微任务宏任务 , 列举一些常见的

微任务
Promise.then async await

宏任务
setTimeout setInterval

对于这一块只需记住 , 从执行顺序上微任务是要先于宏任务的

Promise.then

.then 的微任务

我们现在已经知道了 Promise.then 是一种微任务 , 同时我们还知道微任务是异步任务的一种 , 并且你还突然想起来异步任务不是同步任务 淦整天记的都啥

我们来看一段简单的代码 , 以下代码可以直接在浏览器按 F12 在控制台开始测试

function getP() {
    return new Promise((resolve, reject) => {
    	console.log(0)
        resolve()
    })
}
getP().then(() => console.log(1))
console.log(2)

我们可以看到打印的顺序是 0 2 1
在这里插入图片描述

解释:
已知 : 按照顺序先执行 Promise() , 再执行 .then() , 最后执行 console.log(2)
但是又已知 .then() 是微任务 , 所以就跳出了同步任务 , 在最后执行打印 1 的任务

.then 的使用场景

众所周知 , 我们在发起请求之后 , 就会在回调中使用返回的数据 , 这就是最常见的使用场景了

我们看看下面这段代码

function getP() {
	return new Promise((resolve, reject) => {
		resolve({data:{id:1}})
    })
}
let userId = -1
getP().then(res => userId = res.data.id)

我们为了获得用户的 Id , 必须向后台发起请求 , 并在回调中赋值给页面中的数据

在这里插入图片描述
而有时候我们需要先通过上一个请求获取到数据 , 再使用这个数据进行下一次请求 , 简单来说就是请求的嵌套
请看下面这段代码 , 这是正常使用 promise.then 来获取数据再通过数据发起请求的做法

function getP(id = -1) {
	console.log(id)
	return new Promise((resolve, reject) => {
    	resolve({data:{id:1}})
    })
}
let userId = -1
getP().then(res => {
	userId = res.data.id
	getP(userId)
		.then(() => {})
})

在这里插入图片描述
其实这样倒也没什么问题 , 只是如果需要请求的次数变多 , 还是会出现类似于回调地狱的情况 , 所以才会又出现了 async 和 await 的语法糖

async 和 await

关于这俩只需要记住关键的点就足够了

  • async 和 await 是成双成对的 , 但是使用 async 可以不带 await , 使用 await 必须带上 async
  • 使用 async 修饰的函数必定返回一个 promise 对象 , 如果该函数没有返回值 , 那返回的 promise 对象的成功回调参数为 undefined ; 如果有返回值且不为 promise , 那么返回值是什么成功回调参数就是什么 ; 如果返回值是 promise , 那就不用再说了
  • 使用 await 修饰的请求方法回调将会阻塞当前方法下面的代码执行 , 必须先执行完请求的回调才可以执行下面的代码 , 当然了 await 默认是成功的回调 , 其他回调也可以自己手写
  • 同时 , await 阻塞请求方法下面的代码执行会影响到 async 函数下方的代码执行 , 这个先使用了再说

学习使用

啥也不说了 , 先赶紧学会怎么用 async 和 await 取代 promise 的使用吧

同样是上面的需求

function getP(id = -1) {
	console.log(id)
	return new Promise((resolve, reject) => {
    	resolve({data:{id:1}})
    })
}
async function get(){
	let res = await getP()
	getP(res?.data?.id)
}
get()

在这里插入图片描述
可以看到 , 第 8 行的 res 确实拿到了值并且传递给下一次请求成功打印出了 1

那如果不加 await 呢?

function getP(id = -1) {
	console.log(id)
	return new Promise((resolve, reject) => {
    	resolve({data:{id:1}})
    })
}
function get(){
	let res = getP()
	getP(res?.data?.id)
}
get()

在这里插入图片描述
我们可以看到 , 两次的打印结果都是 -1 , 说明第二次并没有值传递进来

好这样子就可以用 async 和 await 替换 promise 发起请求了

await 的理解与探究

await 的作用实际上就是 阻塞代码执行 , 必须先执行完当前这行代码才能走下去 , 相当于将这行代码以下的代码全部转变成了微任务

请先看我得出的两条结论 , 我们将根据这两条结论解读下面的代码逻辑

  1. 遇到 await 时 , 可以视为将此 await 所在作用域内 await 下方的代码整块全部堵塞 , 堵塞可以视为塞入微任务队列中
  2. 堵塞的代码中包括的 .then 之内和之后的两部分 , 必须要等待 .then 之内的代码执行完成后 , 才能执行 .then 之后的代码 , 必须要等待 .then 之后的代码执行完成后 , 才能执行堵塞代码所在函数的下一行代码 , 其中需要等待的包括同步任务和微任务 , 而宏任务则统一加入到宏任务队列中

注意 : 对于 await.then 中的嵌套 async 和 await 同样满足上述两条结论 , 而对于 await.then 中的非 await 请求 , 则按照 await.then 中的正常情况处理

使用 await

请看以下代码为例子:

代码一

// 打印一个 -1 , 然后返回一个 promise 对象并执行成功回调
function getP() {
	console.log('-1')
    return new Promise((resolve, reject) => {
        resolve(1)
    })
}
// 创立一个定时器 , 并且马上打印输入的参数
function timer(a) {
    setTimeout(() => {
        console.log(a)
    }, 1);
}
// 声明一个函数 , 主要就是调用这个方法
async function testP() {
    console.log('0')
    await getP()
        .then(async () => {
            console.log('1')
            timer('2')
            await getP()
                .then(res => {
                    console.log('3')
                    getP()
                        .then(() => console.log('4'))
                    console.log('5')
                })
            console.log('6')
            timer('7')
        })
    console.log('8')
    getP()
        .then(() => console.log('9'))
    console.log('10')
}
// 声明我们要使用的函数 , 其中调用了上述所有的方法
function test() {
    timer('11')
    testP()
        .then(() => {
            console.log('12')
        })
    timer('13')
    console.log('同步代码最后一句')
}
// 使用函数
test()

我们先来看下执行结果

在这里插入图片描述

接下来我们逐行对上述代码执行过程进行解释 , 请看以下截图 , 因为有行号好讲很多

在这里插入图片描述

  1. 第 112 行执行 test 函数 , 进入第 104 行 , 发现是一个打印 11 的定时器 , 现在将它加入宏任务队列中

此时 , 以下没有就是空
打印:
微任务队列:
宏任务队列: 11

  1. 进入第 105 行 , 执行 testP 函数 , 进入第 83 行 , 直接打印 0

此时 , 以下没有就是空
打印: 0
微任务队列:
宏任务队列: 11

  1. 进入第 84 行 , 执行 getP 函数 , 立马打印 -1 , 由于突然发现 getP 函数前面使用了 await 进行修饰 , 根据结论一 , 所以将 getP 之后的代码执行全部阻塞 , 可以看做是微任务等待处理 , 可以等同看做加入微任务队列

此时 , 以下没有就是空
打印: 0 -1
微任务队列: 阻塞代码
宏任务队列: 11
阻塞代码: 第 85 行 到 第 101 行

  1. 由于 testP 函数中没有同步任务后 , 继续回到第 106 行 , 发现 .then 是 testP 函数的微任务 , 将里面的内容打印 12 加入到微任务队列

此时 , 以下没有就是空
打印: 0 -1
微任务队列: 阻塞代码 12
宏任务队列: 11
阻塞代码: 第 85 行 到 第 101 行

  1. 进入第 109 行 , 定时器是宏任务 , 将打印 13 加入到宏任务队列

此时 , 以下没有就是空
打印: 0 -1
微任务队列: 阻塞代码 12
宏任务队列: 11 13
阻塞代码: 第 85 行 到 第 101 行

  1. 进入第 110 行 , 同步任务直接打印 ‘同步代码最后一句’

此时 , 以下没有就是空
打印: 0 -1 ‘同步代码最后一句’
微任务队列: 阻塞代码 12
宏任务队列: 11 13
阻塞代码: 第 85 行 到 第 101 行

  1. test 函数执行完毕 , 同步任务已经全部完成 , 开始执行微任务队列中的代码 , 遇到阻塞代码 , 开始逐行执行 , 第 86 行直接打印 1 , 第 87 行将打印 2 加入宏任务队列 , 第 88 行执行 getP 函数直接打印 -1 , 发现使用 await 修饰 , 根据结论一 , 将 await.then 下的代码进行堵塞

此时 , 以下没有就是空
打印: 0 -1 ‘同步代码最后一句’ 1 -1
微任务队列: 阻塞代码 12
宏任务队列: 11 13 2
阻塞代码: 第 90 行 到 第96 行 , 第 98 行 到 第 101 行

  1. 根据结论二 , 由于第 90 行 到 第 96 行处在第 84 行的 await.then 内且不为宏任务 , 所以需要等待第 96 行代码执行完后才能继续执行第 98 行 , 进入第 90 行 , 直接打印 3

此时 , 以下没有就是空
打印: 0 -1 ‘同步代码最后一句’ 1 -1 3
微任务队列: 阻塞代码 12
宏任务队列: 11 13 2
阻塞代码: 第 90 行 到 第96 行 , 第 98 行 到 第 101 行

  1. 进入第 91 行 , 直接打印 -1 , 进入第 92 行 , 由于没有 await 修饰 , 根据结论下的注意点 , 这里按照正常将打印 4 的任务加入微任务队列 , 然后进入第 93 行直接打印 5

此时 , 以下没有就是空
打印: 0 -1 ‘同步代码最后一句’ 1 -1 3 -1 5
微任务队列: 阻塞代码 12 4
宏任务队列: 11 13 2
阻塞代码: 第 98 行 到 第 101 行

  1. 此时应该进入第 95 行 , 但是根据结论二 , 需要等待 await.then 中的代码包括同步任务和微任务全部完成才能执行第 95 行 , 所以退回第 92 行将微任务队列中的 4 提前打印为 4

此时 , 以下没有就是空
打印: 0 -1 ‘同步代码最后一句’ 1 -1 3 -1 5 4
微任务队列: 阻塞代码 12
宏任务队列: 11 13 2
阻塞代码: 第 98 行 到 第 101 行

  1. 进入 95 行直接打印 6 , 进入第 96 行根据结论二将 7 加入到宏任务队列中

此时 , 以下没有就是空
打印: 0 -1 ‘同步代码最后一句’ 1 -1 3 -1 5 4 6
微任务队列: 阻塞代码 12
宏任务队列: 11 13 2 7
阻塞代码: 第 98 行 到 第 101 行

  1. 进入第 98 行直接打印 8 , 进入第 99 行执行 getP 函数直接打印 -1 , 进入第 100 行将 9 加入到微任务队列

此时 , 以下没有就是空
打印: 0 -1 ‘同步代码最后一句’ 1 -1 3 -1 5 4 6 8 -1
微任务队列: 阻塞代码 12 9
宏任务队列: 11 13 2 7
阻塞代码: 第 98 行 到 第 101 行

  1. 进入第 101 行直接打印 10 , 此时堵塞代码中的 看起来像同步任务 的代码已经完成 , 根据结论二 , 需要继续完成堵塞代码中的微任务 , 所以退回第 100 行将微任务队列中的 9 提前打印为 9

此时 , 以下没有就是空
打印: 0 -1 ‘同步代码最后一句’ 1 -1 3 -1 5 4 6 8 -1 10 9
微任务队列: 12
宏任务队列: 11 13 2 7
阻塞代码:

  1. 堵塞代码处理完毕 , 继续执行微任务队列 , 直接打印 12

此时 , 以下没有就是空
打印: 0 -1 ‘同步代码最后一句’ 1 -1 3 -1 5 4 6 8 -1 10 9 12
微任务队列:
宏任务队列: 11 13 2 7
阻塞代码:

  1. 微任务队列处理完毕 , 开始执行宏任务队列 , 直接打印 11 13 2 7

此时 , 以下没有就是空
打印: 0 -1 ‘同步代码最后一句’ 1 -1 3 -1 5 4 6 8 -1 10 9 12 11 13 2 7
微任务队列:
宏任务队列:
阻塞代码:

  1. 执行结束 , 打印结果为 0 -1 ‘同步代码最后一句’ 1 -1 3 -1 5 4 6 8 -1 10 9 12 11 13 2 7

好了 , 我们再回顾一次得出的结论

  1. 遇到 await 时 , 可以视为将此 await 所在作用域内 await 下方的代码整块全部堵塞 , 堵塞可以视为塞入微任务队列中
  2. 堵塞的代码中包括的 .then 之内和之后的两部分 , 必须要等待 .then 之内的代码执行完成后 , 才能执行 .then 之后的代码 , 必须要等待 .then 之后的代码执行完成后 , 才能执行堵塞代码所在函数的下一行代码 , 其中需要等待的包括同步任务和微任务 , 而宏任务则统一加入到宏任务队列中

注意 : 对于 await.then 中的嵌套 async 和 await 同样满足上述两条结论 , 而对于 await.then 中的非 await 请求 , 则按照 await.then 中的正常情况处理

不使用 await

在 代码一 的基础上我们这次不使用 await 进行修饰 , 所以请看以下代码

代码二
我们做的修改仅仅是将 testP 函数中的 async 和 await 删掉了 , 保留开始的 async 是为了能返回一个 promise 对象

// 打印一个 -1 , 然后返回一个 promise 对象并执行成功回调
function getP() {
	console.log('-1')
    return new Promise((resolve, reject) => {
        resolve(1)
    })
}
// 创立一个定时器 , 并且马上打印输入的参数
function timer(a) {
    setTimeout(() => {
        console.log(a)
    }, 1);
}
// 声明一个函数 , 主要就是调用这个方法
async function testP() {
    console.log('0')
    getP()
        .then(() => {
            console.log('1')
            timer('2')
            getP()
                .then(res => {
                    console.log('3')
                    getP()
                        .then(() => console.log('4'))
                    console.log('5')
                })
            console.log('6')
            timer('7')
        })
    console.log('8')
    getP()
        .then(() => console.log('9'))
    console.log('10')
}
// 声明我们要使用的函数 , 其中调用了上述所有的方法
function test() {
    timer('11')
    testP()
        .then(() => {
            console.log('12')
        })
    timer('13')
    console.log('同步代码最后一句')
}
// 使用函数
test()

我们先来看看执行结果是什么

在这里插入图片描述
这个其实很简单的了 , 里面可能让人纠结的一点就是微任务队列中再次出现微任务时 , 新的微任务放在哪里 , 答案就是新的微任务放在旧的微任务队列中的最后面 , 这就是为什么执行顺序是 3 会在 12 的后面而不是在 9 的前面

结论

  1. 遇到 await 时 , 可以视为将此 await 所在作用域内 await 下方的代码整块全部堵塞 , 堵塞可以视为塞入微任务队列中
  2. 堵塞的代码中包括的 .then 之内和之后的两部分 , 必须要等待 .then 之内的代码执行完成后 , 才能执行 .then 之后的代码 , 必须要等待 .then 之后的代码执行完成后 , 才能执行堵塞代码所在函数的下一行代码 , 其中需要等待的包括同步任务和微任务 , 而宏任务则统一加入到宏任务队列中

注意 : 对于 await.then 中的嵌套 async 和 await 同样满足上述两条结论 , 而对于 await.then 中的非 await 请求 , 则按照 await.then 中的正常情况处理

结束

其实写的比较复杂 , 而且结论我也不敢保证肯定对 , 但是目前就是这样用着
其实你完全不用在乎这些 , 因为除了面试题以外也很少会让你写这样的语句 , 而且你多半也不会这样写
有什么问题赶紧发评论留言大家一起讨论讨论啊
你可以复制下面的 HTML 代码在浏览器的控制台中进行测试

文件代码复制测试

<!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>异步</title>
    <style>
        button {
            padding: 10px;
        }
    </style>
</head>

<body>
    <button onclick="queryPromise()">queryPromise</button>
    <pre>
        async function queryPromise() {
            let obj1
            let obj2
            obj1 = await getPromise()
            obj2 = await getPromise(obj1.id)
    
            console.log('obj1', obj1)
            console.log('obj2', obj2)
        } 
        function getPromise(id = 20) {
            return new Promise((resolve, reject) => {
                let obj
                if (id == 20) {
                    obj = {
                        id: 12,
                        name: '张三'
                    }
                } else if (id == 12) {
                    obj = {
                        id: 20,
                        name: '邵雅虎'
                    }
                } else {
                    obj = {
                        id: -1,
                        name: '查无此人'
                    }
                }
                resolve(obj)
            })
        }
    </pre>
    <hr>
    <button onclick="queryP()">queryP</button>
    <pre>
        async function queryP() {
            await getP()
            console.log(1)
            timer(2)
            getP()
                .then(() => {
                    timer(4)
                    console.log(3)
                })
            console.log(5)
            timer(6)
            return new Promise((resolve, reject) => {
                resolve('结束')
            })
        }
        function getP() {
            console.log('-1')
            return new Promise((resolve, reject) => {
                resolve(1)
            })
        }
        function timer(a) {
            setTimeout(() => {
                console.log(a)
            }, 1);
        }
    </pre>
    <hr>
    <button onclick="test()">test</button>
    <pre>
        function getP() {
            console.log('-1')
            return new Promise((resolve, reject) => {
                resolve(1)
            })
        }
        function timer(a) {
            setTimeout(() => {
                console.log(a)
            }, 1);
        }
        async function testP() {
            console.log('0')
            await getP()
                .then(async () => {
                    console.log('1')
                    timer('2')
                    await getP()
                        .then(res => {
                            console.log('3')
                            getP()
                                .then(() => console.log('4'))
                            console.log('5')
                        })
                    console.log('6')
                    timer('7')
                })
            console.log('8')
            getP()
                .then(() => console.log('9'))
            console.log('10')
        }
        function test() {
            timer('11')
            testP()
                .then(() => {
                    console.log('12')
                })
            timer('13')
            console.log('同步代码最后一句')
        }
    </pre>
</body>
</html>
<script>
    async function queryPromise() {
        let obj1
        let obj2
        obj1 = await getPromise()
        obj2 = await getPromise(obj1.id)

        console.log('obj1', obj1)
        console.log('obj2', obj2)
    }
    function getPromise(id = 20) {
        return new Promise((resolve, reject) => {
            let obj
            if (id == 20) {
                obj = {
                    id: 12,
                    name: '张三'
                }
            } else if (id == 12) {
                obj = {
                    id: 20,
                    name: '邵雅虎'
                }
            } else {
                obj = {
                    id: -1,
                    name: '查无此人'
                }
            }
            resolve(obj)
        })
    }
    async function queryP() {
        await getP()
        console.log(1)
        timer(2)
        getP()
            .then(() => {
                timer(4)
                console.log(3)
            })
        console.log(5)
        timer(6)
        return new Promise((resolve, reject) => {
            resolve('结束')
        })
    }
    function getP() {
        console.log('-1')
        return new Promise((resolve, reject) => {
            resolve(1)
        })
    }
    function timer(a) {
        setTimeout(() => {
            console.log(a)
        }, 1);
    }
    async function testP() {
        console.log('0')
        await getP()
            .then(async () => {
                console.log('1')
                timer('2')
                await getP()
                    .then(res => {
                        console.log('3')
                        getP()
                            .then(() => console.log('4'))
                        console.log('5')
                    })
                console.log('6')
                timer('7')
            })
        console.log('8')
        getP()
            .then(() => console.log('9'))
        console.log('10')
    }
    function test() {
        timer('11')
        testP()
            .then(() => {
                console.log('12')
            })
        timer('13')
        console.log('同步代码最后一句')
    }
</script>

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

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

相关文章

【金三银四系列】Spring面试题-下(2023版)

Spring面试专题 1.介绍下Spring的初始化过程 Spring的初始化过程中会走refresh方法&#xff0c;这是个模板模式的实现&#xff0c;包含有如下的14个方法 每个方法的相关作用 把每个方法的作用按照这个图介绍下就可以了 2.配置文件的加载解析 Spring初始化的时候在obtainFresh…

内存管理框架---页(一)

文章目录物理内存的模型非一致内存访问--NUMA一致内存访问模型--UMA内存管理架构页页框管理页描述符页描述符字段flags字段详解gfp_mask 标志获得页alloc_pages__get_free_pages获得填充为0的页释放页kmallocvmalloc参考资料你用心写的每一篇文章&#xff0c;可能会带别人和自己…

【华为OD机试模拟题】用 C++ 实现 - 选座位(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 分积木(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 吃火锅(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - RSA 加密算法(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 构成的正方形数量(2023.Q1) 【华为OD机试模拟…

特征向量中心度(eigenvector centrality)算法原理与源码解析

前言 随着图谱应用的普及&#xff0c;图深度学习技术也逐渐被越来越多的数据挖掘团队所青睐。传统机器学习主要是对独立同分布个体的统计学习&#xff0c;而图深度学习则是在此基础上扩展到了非欧式空间的图数据之上&#xff0c;通过借鉴NLP和CV方向的模型思想&#xff0c;衍生…

供应商关系有哪些类型?如何优化管理?

供应商关系有两种主要类型。识别你与供应商的关系类型将有助于你有效地管理期望和调整目标。 1、垂直供应商关系 在垂直供应商关系中&#xff0c;供应链以卖方和买方之间的传统方式联系起来。各方都把重点放在确保个人和供应链目标的实现上。垂直供应商关系的例子包括分销商…

JVM面试总结

文章目录栈帧中存放的信息&#xff1a;对象的创建过程对象的内存布局&#xff1f;对象的访问定位方式&#xff1f;如何判断对象已死&#xff1f;可以作为GC Root的点&#xff1a;谈一下引用对象再被回收时如何逃脱&#xff1f;回收方法区如何判断常量是否废弃&#xff1f;垃圾回…

IMX Yocto SDK 拉取报错误fatal: Could not read from remote repository

IMX 平台Yocto SDK拉取步骤拉取步骤可以在NXP官方yocto指导文档里查看&#xff0c;这里再贴一次&#xff0c;然后针对的讲可能遇到的问题。1&#xff0c;首先下载repo。repo是谷歌开发的一款python小程序。是基于GIT工作的&#xff0c;可以批量拉取&#xff0c;合并多个代码仓库…

Springboot 使用thymeleaf 服务器无法加载resources中的静态资源异常处理

目录一、异常错误二、原因三、解决方法方法1. 将无法编译的静态资源放入可编译目录下方法2. 重新编译项目加载资源方法3. 修改pom.xml资源配置文件方法4. 不连接远程数据库启动&#xff0c;使用本地数据库一、异常错误 Springboot使用thymeleaf&#xff0c;并连接远程数据库启…

Vue3电商项目实战-商品详情模块5【14-商品详情-数量选择组件、15-商品详情-按钮组件、16-商品详情-同类推荐组件】

文章目录14-商品详情-数量选择组件15-商品详情-按钮组件16-商品详情-同类推荐组件14-商品详情-数量选择组件 目的&#xff1a;封装一个通用的数量选中组件。 大致功能分析&#xff1a; 默认值为1可限制最大最小值点击-就是减1 点击就是加1需要完成v-model得实现存在无label情况…

如何构建以应用为核心的运维体系

在微服务的架构模式下&#xff0c;我们的运维视角一定转到应用这个核心概念上来&#xff0c;一切要从应用的角度来分析和看待问题。 微服务架构一般都是从单体架构或分层架构演进过来的。软件架构服务化的过程&#xff0c;就是我们根据业务模型进行细化的过程&#xff0c;在这…

并发编程学习篇并发线程池底层原理详解与源码分析

一、线程池与线程对比 package bat.ke.qq.com.threadpool;import java.util.ArrayList; import java.util.List; import java.util.Random;/**** 使用线程的方式去执行程序*/ public class ThreadTest {public static void main(String[] args) throws InterruptedException {…

为Webpack5项目引入Buffer Polyfill

前言 最近在公司的一个项目中使用到了Webpack5&#xff0c; 然而在使用某个npm包的时候&#xff0c;出现了Buffer is not defined 这个问题&#xff0c;原因很明显了&#xff0c;因为浏览器运行时没有Buffer这个API&#xff0c;所以需要为浏览器引入Buffer Polyfill. Webpack5…

如何制定达人营销策略

如今&#xff0c;达人营销不再是一个新兴趋势&#xff0c;而是公司整个数字营销战略的一部分。虽然十年前&#xff0c;达人还不存在&#xff0c;但随着公司对数字化营销依赖度地提升&#xff0c;各个领域的大V群体逐渐壮大&#xff0c;越来越多的公司已经采用了达人营销策略。如…

JavaScript 库

文章目录JavaScript 库JavaScript 框架&#xff08;库&#xff09;jQueryPrototypeMooTools其他框架CDN -内容分发网络引用 jQuery使用框架JavaScript 库 JavaScript 库 - jQuery、Prototype、MooTools。 JavaScript 框架&#xff08;库&#xff09; JavaScript 高级程序设计…

界面控件DevExtreme的Data Grid组件——让业务信息管理更轻松!

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#xff0c;使您可以利用现代Web开发堆栈&#xff08;包括React&#xff0c;Angular&#xff0c;ASP.NET Core&#xff0c;jQuery&#xff0c;Knockout等&#xff09;构建交互式的Web应用程序&#xff0c;该套件附带功能齐…

【阿旭机器学习实战】【35】员工离职率预测---决策树与随机森林预测

【阿旭机器学习实战】系列文章主要介绍机器学习的各种算法模型及其实战案例&#xff0c;欢迎点赞&#xff0c;关注共同学习交流。 本文的主要任务是通过决策树与随机森林模型预测一个员工离职的可能性并帮助人事部门理解员工为何离职。 目录1.获取数据2.数据预处理3.分析数据3.…

Python之正则表达式细讲

文章目录前言一、行定位符二、元字符三、限定符四、字符类五、排除字符六、选择字符七、转义字符八、分组九、正则表达式语法总结前言 在处理字符串时&#xff0c;经常会有查找符合某些复杂规则的字符串的需求。比如用爬虫批量抓取某网站图片&#xff0c;要从抓下来的网页信息中…

【AI写作】 机器人流程自动化 介绍 - Robotic Process Automation (RPA) Introduction

写一篇文章介绍RPA技术,未来的发展。使用markdown格式,有3级索引,超过3000字。 某位大师说过的: 任何行业、任何部门都有大量的场景,涉及重复、有规则逻辑的工作,都可以用 RPA 开发一个软件机器人帮助完成。 文章目录 机器人过程自动化(RPA)简介RPA的定义RPA的好处Robo…

国内“谁”能实现chatgpt,短期穷出的类ChatGPT简评(算法侧角度为主),以及对MOSS、ChatYuan给出简评,一文带你深入了解宏观技术路线。

1.ChatGPT简介【核心技术、技术局限】 ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer&#xff09;&#xff0c;美国OpenAI 研发的聊天机器人程序 &#xff0c;于2022年11月30日发布 。ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c…

这周末,StarRocks 邀请开发者们一起来上海 GAIDC 开源集市,各种任务等你来挑战!

2 月 25 日-26 日 &#xff08;本周末&#xff09;2023 全球人工智能开发者先锋大会&#xff08;GAIDC&#xff09;将于上海临港中心举行&#xff01;StarRocks 社区受邀参与开源集市&#xff0c;展示开源魅力、分享社区成果。欢迎上海的同学们到“摊位”上与工作人员互动&…