本文深入解析JavaScript中async/await机制,阐述如何将异步操作转化为同步逻辑。通过封装Promise处理AJAX请求,演示如何利用async函数和await关键字实现串行执行,避免回调地狱。文章涵盖语法规范、执行流程及sleep函数实现,帮助开发者掌握现代JS异步处理核心技巧。
JavaScript异步函数async function变同步函数入门
在JavaScript中,异步函数的特殊性在于其执行完成的时间点及耗时无法由人为主观预测。
因此,不能简单地通过设置定时函数来确保前一个程序执行完毕后立即调用下一个函数。
接续前文:js 异步获取到的数据 到底能不能 赋值给一个全局变量
Promise因此凸显了其价值,它能明确当前程序执行的阶段及结果。通过新建一个Promise对象,可以追踪异步状态。
new Promise(function (resolve, reject) {
// 要做的事情...
});尝试进行一次AJAX请求。
<script>
var goodsInfo = {};
$(document).ready(function(){
// 使用Promise
new Promise(function (resolve,reject) {
$.ajax({url:"https://api-hmugo- web.itheima.net/api/public/v1/home/catitems",success:function(result){
goodsInfo = result;
resolve(goodsInfo);
console.log(goodsInfo);
}});
}).then(function () {
console.log(goodsInfo);
})
console.log(1);
console.log(goodsInfo);
});
</script>
检查是否在.then()回调中获取到经过AJAX请求赋值后的全局变量goodsInfo的值。若需对goodsInfo进行后续操作,均应在.then中进行。
由于AJAX在项目中使用频繁,将其封装为独立函数将更为便捷。
<script>
var goodsInfo = {};
$(document).ready(function(){
// 封装一个 promise 函数,在promiise对象前面多加了一个return
function promiseFun (url){
return new Promise(function (resolve,reject) {
$.ajax({url:url,success:function(result){
goodsInfo = result;
resolve(goodsInfo);
console.log(goodsInfo);
}});
})
}
// 调用函数
promiseFun("https://api-hmugo-web.itheima.net/api/public/v1/home/catitems").then(function () {
console.log(goodsInfo);
})
console.log(1);
console.log(goodsInfo);
});
</script>
结果保持一致,但调用方式更加简洁。此时使用async function感觉似乎又回到了异步逻辑中。
// 定义规则
async function asyncFunc() {
// await 后面必须是定义过的 promise function
await myfunction();
await youfunction();
await shefunction();
somefunction();
xxxxxx;
}
asyncFunc();<script>
var goodsInfo = {};
var data ={};
$(document).ready(function(){
// 先定义一个 promise function
function promiseFun (url){
return new Promise(function (resolve,reject) {
$.ajax({url:url,success:function(result){
goodsInfo = result;
resolve(goodsInfo);
console.log(goodsInfo);
}});
})
}
// 在定义一个 asyns function
async function asyncFuunc(){
// 看这里面的代码执行顺序是不是跟同步函数简直一模一样
await promiseFun("https://api-hmugo-web.itheima.net/api/public/v1/home/catitems");
console.log(goodsInfo);
data=goodsInfo;
console.log(data)
console.log(2);
}
// 调用 asyns 函数
asyncFuunc();
console.log(1);
console.log(goodsInfo);
});
</script>
异步函数(async/await)
异步函数
异步函数,亦称“async/await”(语法关键字),是ES6期约模式在ECMAScript函数中的具体应用。async/await属于ES8规范新增内容,旨在解决利用异步结构组织代码的复杂性。
- async
async关键字用于声明异步函数。该关键字可应用于函数声明、函数表达式、箭头函数及类方法上。
async function foo() {}
let bar = async function() {};
let baz = async() => {};
class Qux {
async qux() {}
}若异步函数使用return返回了值(若无return则返回undefined),该返回值会被Promise.resolve()包装成一个期约对象。
async function foo(){
console.log(1)
}
console.log(foo()); //promise {<fulfilled>:undefined}
foo().then(console.log) //undefined
console.log(2)
//1
//2
//undefined- await
await关键字可暂停异步函数代码的执行,等待期约解决。await会暂停执行异步函数后续的代码,从而让出JavaScript运行时的执行线程。此行为与生成器函数中的yield关键字类似。await同样尝试“解包”对象的值,将该值传给表达式,随后异步恢复异步函数的执行。
await关键字必须在异步函数内部使用;异步函数的特性不会扩展到嵌套函数中,否则将抛出SyntaxError。
async function foo(){
await Promise.resolve(3);
}
foo();在async/await中真正起作用的是await。若异步函数不包含await关键字,其执行过程与普通函数基本无异。
当JavaScript运行时遇到await关键字时,会记录暂停执行的位置。一旦await右侧的值可用,JS运行时会向消息队列中推送一个任务,该任务负责恢复异步函数的执行。
因此,即使await后面跟随的是一个立即可用的值,函数的其他部分仍会被异步求值。
async function foo() {
console.log(2);
await null;
console.log(4);
}
console.log(1);
foo();
console.log(3);
// 1
// 2
// 3
// 4
控制台中输出结果的顺序很好地解释了运行时的工作过程:
(1)打印1;
(2)调用异步函数foo();
(3)(在foo()中)打印2;
(4)(在foo()中)await关键字暂停执行,为立即可用的值null向消息队列中添加一个任务;
(5)foo()退出;
(6)打印3;
(7)同步线程的代码执行完毕;
(8)JavaScript运行时从消息队列中取出任务,恢复异步函数执行;
(9)(在foo()中)恢复执行,await取得null值(这里并没有使用);
(10)(在foo()中)打印4;
(11)foo()返回。异步函数策略
- 实现sleep()函数
许多初学者在学习JavaScript时,希望找到类似Java中Thread.sleep()的函数,以便在程序中插入非阻塞暂停。过去,这一需求通常通过setTimeout()利用JavaScript运行时的行为来实现。
引入异步函数后,情况发生了变化。一个简单的箭头函数即可实现sleep()功能。
async function sleep(delay) {
return new Promise((resolve) => setTimeout(resolve, delay));
}
async function sleepfoo(){
const t0 = Date.now();
await sleep(2000);
const t1 = Date.now();
console.log(t1 - t0);
}
sleepfoo()
//2002 任务队列执行,时间不一定- 利用平行执行
- 串行执行期约
- 栈追踪与内存管理
注意:
异步函数是将期约应用于JavaScript函数的结果。异步函数可以暂停执行,而不阻塞主线程。无论是编写基于期约的代码,还是组织串行或平行执行的异步代码,使用异步函数都非常得心应手。异步函数可以说是现代JavaScript工具箱中最重要的工具之一。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持本站。