js中的同步方法及异步方法
目录
1.代码说明
2.async修饰的方法和非async修饰的方法的区别
3.不使用await的场景
4.总结
1.代码说明
const saveTem = () => {// 校验处理const res = check()if (!res) {return}addTemplateRef.value.openModal()
}
这段代码中,check方法返回的是true和false,是一个普通方法,
openModal也是一个普通方法,没有返回值,
这段代码的执行顺序是依次执行的,因为没有任何异步操作,即使这个方法被async修饰,代码的执行顺序也是依次执行的
什么是异步操作,可以简单理解为方法被async修饰,axios及fetch请求及setTimeout方法等。
返回值为promise的方法不一定为异步方法,也就是说异步方法不能通过返回值进行判断
但是异步方法的返回值一定是promise,必须使用await或者.then才能获取实际返回值
2.async修饰的方法和非async修饰的方法的区别
1. 返回值不同
async 函数:
-
总是返回一个 Promise 对象
-
如果返回非 Promise 值,会自动用 Promise 包装
-
如果抛出异常,返回被拒绝(rejected)的 Promise
普通函数:
-
直接返回 return 语句指定的值
-
如果没有 return,返回 undefined
-
抛出异常会直接中断执行
2. 执行方式不同
async 函数:
-
内部可以使用 await 暂停执行,使用await后会等待后面的方法执行完成,再继续后续的内容
-
不会阻塞主线程
普通函数:
-
同步执行
-
会阻塞后续代码直到执行完成
async function asyncFunc() {console.log(1);await new Promise(resolve => setTimeout(resolve, 1000));console.log(2);
}function syncFunc() {console.log(1);setTimeout(() => console.log(2), 1000);console.log(3);
}asyncFunc(); // 输出: 1, 2 (1秒后)
syncFunc(); // 输出: 1, 3, 2 (1秒后)
3. 错误处理不同
async 函数:
-
抛出的错误会被捕获并转换为 rejected Promise
-
需要使用 try/catch 或 .catch() 捕获错误
普通函数:
-
错误会直接抛出
-
需要使用 try/catch 捕获同步错误
4. 调用方式不同
async 函数:
-
必须用 await 或 .then() 才能获取结果
-
直接调用会返回 Promise 对象而非实际结果
普通函数:
-
直接调用获取返回值
5. 适用场景
使用 async 函数的场景:
-
需要处理 Promise 链式调用,使用之前的.then会导致回调地狱问题,使用await可以让多个异步操作按照顺序执行,使代码更加整洁
-
需要顺序执行多个异步操作
-
需要更清晰的异步代码结构
使用普通函数的场景:
-
纯同步操作
示例
async function getData() {console.log('开始获取数据...'); // 1. 同步执行const result = await fetchData(); // 2. 遇到 await,暂停执行并等待 Promise 解决console.log(result); // 4. Promise 解决后继续执行return result; // 5. 返回结果(包装在 Promise 中)
}// 模拟异步函数
function fetchData() {return new Promise(resolve => {setTimeout(() => resolve('数据获取成功'), 1000); // 3. 1秒后解决 Promise});
}// 调用示例
getData().then(data => console.log('最终结果:', data)); // 6. 接收最终结果
详细执行流程:
-
同步阶段:
-
调用
getData()
函数 -
执行第一行
console.log('开始获取数据...')
(立即输出)
-
-
遇到 await:
-
执行
fetchData()
(返回一个 Promise) -
await
会暂停getData()
函数的执行,将控制权交回事件循环 -
此时
getData()
返回一个未解决的 Promise,pending状态的promise
-
-
异步等待:
-
fetchData()
中的setTimeout
开始计时(1秒) -
JavaScript 引擎可以处理其他任务
-
-
Promise 解决:
-
1秒后,
setTimeout
回调执行,Promise 被解决(resolve) -
await
接收到解决的值'数据获取成功'
-
getData()
函数恢复执行
-
-
继续执行 async 函数:
-
将解决的值赋给
result
-
执行
console.log(result)
(输出 "数据获取成功") -
执行
return result
(这里会包装成一个promise)
-
-
处理最终结果:
-
.then()
回调被执行,输出 "最终结果: 数据获取成功"
-
关键点说明:
-
await
会暂停当前 async 函数的执行(但不会阻塞主线程) -
async 函数在遇到第一个
await
时就会立即返回一个 Promise -
被暂停的函数会在 Promise 解决后从暂停点继续执行
-
return 的值会自动包装成 Promise
3.不使用await的场景
场景 1:明确需要 Promise
对象时
const fetchData = async () => { /* ... */ };// 需要传递 Promise 给其他逻辑
const promise = fetchData(); // 不 await,保留 Promise
promise.then((data) => { /* ... */ });
场景 2:并行多个异步任务(用 Promise.all
)
const getUser = async () => { /* ... */ };
const getPosts = async () => { /* ... */ };// 不单独 await,直接收集 Promises
const [user, posts] = await Promise.all([getUser(), getPosts()]);
关键点说明
-
并行执行:
getUser()
和getPosts()
会同时开始执行,而不是一个接一个执行。 -
Promise.all 的作用:
-
接收一个 Promise 数组作为输入
-
返回一个新的 Promise,当所有输入的 Promise 都解决(resolve)时,这个新 Promise 才会解决
-
解决值是一个数组,包含所有输入 Promise 的解决值,顺序与输入数组一致
-
-
解构赋值:
const [user, posts] = ...
将 Promise.all 返回的数组解构为两个变量
执行流程
-
调用
getUser()
和getPosts()
会立即返回两个 Promise 对象 -
这两个异步操作会同时开始执行(假设它们不互相依赖)
-
Promise.all
会等待这两个 Promise 都完成 -
当两者都完成后,结果会被解构到
user
和posts
变量中
与顺序执行的对比
如果写成这样就是顺序执行(不推荐):
const user = await getUser(); // 等待这个完成
const posts = await getPosts(); // 然后才开始这个
而使用 Promise.all
的方式总耗时大约等于较慢的那个操作的时间,而不是两者时间相加。
注意事项
-
如果其中一个 Promise 被拒绝(reject),整个
Promise.all
会立即拒绝 -
适合用于彼此独立的异步操作
-
如果操作之间有依赖关系,可能需要顺序执行
4.总结
方法中如果没有异步方法,按照顺序依次执行
如果有异步方法,没有使用await或者.then,不会依次执行,会先执行异步方法后面的方法,再执行异步方法
如果需要控制方法内,异步方法的顺序,可以使用await或者.then,需要注意如果要使用await,则方法必须被async修饰
使用async修饰的方法,返回值为promise,需要使用await或者.then获取返回值
返回值为promise不一定是异步方法,异步方法的返回值一定是promise
常见的异步方法为async修饰的方法,setimeout方法,axios方法,fetch方法