JavaScript 是一种单线程的语言,这意味着 JavaScript 一次只能执行一个操作。然而,JavaScript 中有很多异步的特性,包括事件处理、定时器、Ajax 请求、Promise、async/await 等机制。
这些异步特性使得 JavaScript 能够处理大量的网络请求、定时任务、用户交互等操作,而不会阻塞程序的执行。通过合理地利用这些异步特性,JavaScript 能够提供更流畅的用户体验,并且能够处理复杂的并发操作。
通过阅读以下几个知识点可以帮助我们理解如何控制异步代码的执行
1. 回调函数
2. Promise对象
3. then方法
4. async/await
回调函数
在 JavaScript 中,回调函数是一种常见的编程模式,用于处理异步操作和事件驱动的代码。回调函数是一个作为参数传递给其他函数的函数,在特定的事件发生或异步操作完成后被调用。
javascript
function a(cb){
setTimeout(()=>{
console.log('A');
cb();
},1000)
}
function b(){
setTimeout(()=>{
console.log('B');
},500)
}
a(b);
在这段代码中,调用 a
函数,并将参数 b
作为回调函数传入。在 a
函数内部,调用 setTimeout
函数并传入一个回调函数和延迟时间为 1000 毫秒。回调函数中打印出字母 'A',然后调用回调函数 cb
。回到 a
函数外部,此时 b
函数已经被传入到 a
函数内部。继续执行 b
函数之前,等待 1000 毫秒,即 a
函数内部的 setTimeout
完成后再执行。
通过使用回调函数,可以确保代码在异步操作或事件完成后得到正确的执行顺序。然而,使用过多的回调函数可能会导致代码可读性下降和出现回调地狱的问题,回调地狱会使得代码的维护变得异常的困难。为了解决这个问题,ES6 引入了 Promise 和 async/await 等更高级的异步处理机制。
Promise对象
Promise 是一种用于处理异步操作的对象。Promise 主要用于解决回调地狱和处理异步代码的可读性。
scss
function xq(){
return new Promise((resolve, reject) =>{
setTimeout(()=>{ //定时器
console.log('a');
resolve();// 成功完成异步操作,将数据作为参数传递给 resolve 方法
},2000) //两秒后执行
})
}
function baby(){
console.log('c');
}
xq().then(()=>{ //打印a
baby(); //打印b
});
在上面的示例中,通过 Promise 构造函数创建了一个 Promise 对象,并执行异步操作。当异步操作成功完成时,调用 resolve()
方法将数据作为参数传递给 then
方法中的回调函数。
Promise 对象可以通过调用 then 方法来添加成功处理函数和失败处理函数。then 方法接收两个参数:第一个参数是成功处理函数,第二个参数是失败处理函数。这些处理函数在 Promise 对象状态改变时被调用。
then方法
在 JavaScript 中,then
是 Promise 对象的一个方法,用于指定当 Promise 对象状态变为 resolved(成功)时要执行的回调函数。then
方法接受两个参数:第一个参数是 Promise 成功时执行的回调函数,第二个参数(可选)是 Promise 失败时执行的回调函数。这两个参数都是函数类型。
javascript
function xq(){
return new Promise((resolve, reject) =>{
setTimeout(()=>{
console.log('a');
resolve();// 成功完成异步操作,将数据作为参数传递给 resolve 方法
},2000)
})
}
function marry(){
return new Promise((resolve, reject) =>{
setTimeout(()=>{
console.log('b');
resolve();
},1000)
});
}
function baby(){
console.log('c');
}
xq().then(()=>{ //打印a
return marry()
})
.then(()=>{ //打印b
baby(); //打印c
});
JavaScript是单线程的语言,它在遇到定时器等异步的代码时,会将这个线程挂起然后去执行其他的同步代码。通过使用then方法可将原本会挂起的异步代码立即执行。当异步操作成功完成时,调用 resolve()
方法将数据作为参数传递给 then
方法中的回调函数。
then
方法也返回一个 Promise 对象,因此可以链式调用多个 then
方法来处理一系列异步操作的结果。因此在这段代码中可以实现控制函数的执行顺序做到a,b,c依次打印。
async/awiat
使用 async 关键字声明一个函数时,该函数会返回一个 Promise 对象。在函数体内部,使用 await 关键字可以暂停函数的执行,等待 Promise 对象完成,并返回 Promise 的结果。
javascript
async function myAsyncFunction() {
try {
const result = await myPromise; // 等待异步操作的结果
console.log(result);
} catch (error) {
console.error(error);
}
}
myAsyncFunction();
在上面的代码中,我们使用 async
关键字声明了一个异步函数 myAsyncFunction
。在函数体内部,我们使用 await
关键字等待一个返回 Promise
对象的表达式 myPromise
。当 myPromise
被解析时,结果会被赋值给 result
,然后我们可以在函数中继续处理 result
。如果 myPromise
被拒绝,那么错误信息会被捕获并传递给 catch
块进行处理。
使用 async/await
可以让异步代码看起来更像同步代码,使得逻辑更加清晰和易于理解。然而,需要注意的是,await
关键字只能在异步函数内部使用,而且它只能等待返回 Promise
的表达式,因此在使用时需要注意函数的上下文和语法规则。