目录
- setTimeout、Promise、Async/Await 的区别
- **setTimeout**:
- 思路
- 需要注意的
- **Promise**:
- 思路
- 需要注意的
- **Async/Await**:
- 思路
- 需要注意的
- 总结
setTimeout、Promise、Async/Await 的区别
setTimeout:
- 概念:
setTimeout
是JavaScript中的一个函数,用于在一定的时间间隔后执行指定的代码。
console.log('script start') //1. 打印 script start
setTimeout(function(){
console.log('settimeout') // 4. 打印 settimeout
}) // 2. 调用 setTimeout 函数,并定义其完成后执行的回调函数
console.log('script end') //3. 打印 script start
// 输出顺序:script start->script end->settimeout
思路
console.log('script start')
:立即在主线程中执行,打印出"script start"。setTimeout(function(){ console.log('settimeout') })
:调用setTimeout
函数,并定义其完成后执行的回调函数,但没有指定延迟的时间。因此,回调函数将会被添加到任务队列中,等待主线程执行完毕后立即执行。console.log('script end')
:立即在主线程中执行,打印出"script end"。
由于setTimeout
的回调函数并未设置延迟,它会在主线程执行完毕后立即执行,因此输出顺序应该是:script start -> script end -> settimeout。
需要注意的
setTimeout
的回调函数在这里并没有设置延迟时间,因此会立即执行。- JavaScript 运行环境中存在着主线程和任务队列,当主线程执行完毕后,会去检查任务队列中是否有任务需要执行,这时才会执行
setTimeout
的回调函数。
// 使用setTimeout模拟一个简单的延迟操作,输出一条消息console.log('Start') // 同步操作// 模拟延迟操作,2秒后输出消息
setTimeout(() => {console.log('Delayed message after 2 seconds')
}, 2000)console.log('End') // 同步操作
在这个案例中,setTimeout
函数用于模拟一个简单的延迟操作。在代码执行时,会先输出"Start"和"End"(同步操作),然后等待2秒后输出"Delayed message after 2 seconds"。需要注意的是,setTimeout
不会阻塞后续的代码执行,而是在指定的时间后将回调函数加入到任务队列中,等待执行。
setTimeout
允许我们在指定的时间后执行一段代码,它是一种简单的异步操作方式。
- 需要注意:需要注意的是,
setTimeout
并不会阻塞后续的代码执行,而是在指定的时间后将回调函数加入到任务队列中,等待执行。
Promise:
- 概念:Promise是ES6中引入的一种用于处理异步操作的对象,代表了一个异步操作最终会产生的值或原因。
console.log('script start')
let promise1 = new Promise(function (resolve) {console.log('promise1')resolve()console.log('promise1 end')
}).then(function () {console.log('promise2')
})
setTimeout(function () {console.log('settimeout')
})
console.log('script end')
思路
console.log('script start')
:立即在主线程中执行,打印出"script start"。let promise1 = new Promise(function (resolve) { ... })
:创建一个新的Promise对象,立即执行传入的函数。在这个函数中:console.log('promise1')
:立即在主线程中执行,打印出"promise1"。resolve()
:立即将Promise状态从pending变为fulfilled。console.log('promise1 end')
:立即在主线程中执行,打印出"promise1 end"。
.then(function () { console.log('promise2') })
:注册在Promise对象状态变为fulfilled后执行的回调函数,但是由于Promise状态已经是fulfilled,所以这个回调函数会被添加到微任务队列中,等待主线程执行完毕后立即执行。setTimeout(function(){ console.log('settimeout') })
:调用setTimeout
函数,并定义其完成后执行的回调函数,但没有指定延迟的时间。因此,回调函数会被添加到任务队列中,等待主线程执行完毕后立即执行。console.log('script end')
:立即在主线程中执行,打印出"script end"。
由于微任务(Promise)优先级高于宏任务(setTimeout),且Promise对象的状态已经是fulfilled,因此输出顺序应该是:script start -> promise1 -> promise1 end -> script end -> promise2 -> settimeout。
需要注意的
- Promise对象中的函数是立即执行的,而
.then()
中的回调函数是异步执行的,会被添加到微任务队列中。 - 微任务(Promise)会优先于宏任务(setTimeout)执行。
// 使用Promise模拟一个简单的异步操作,比如模拟加载数据// 模拟异步操作,返回一个Promise对象
function loadData() {return new Promise((resolve, reject) => {// 模拟异步操作,比如从服务器获取数据setTimeout(() => {const data = 'Simulated data loaded'resolve(data) // 异步操作成功,将数据传递给resolve}, 2000)})
}// 调用模拟的异步操作
loadData().then(data => {console.log(data) // 在异步操作成功后输出数据}).catch(error => {console.error('Error:', error) // 捕获可能出现的错误})
在这个案例中,loadData
函数返回一个Promise对象,模拟了一个简单的异步操作(比如从服务器获取数据)。通过setTimeout
模拟了2秒的延迟,然后将数据传递给resolve
,表示异步操作成功。在调用loadData
后,使用.then()
方法处理异步操作成功的情况,并使用.catch()
方法捕获可能出现的错误。这样可以更好地管理异步操作的状态和结果。
Promise提供了一种更结构化和灵活的处理异步操作的方式,可以通过.then()
方法链式处理异步操作的结果。
- 需要注意:需要注意的是,Promise可以处于pending、fulfilled或rejected三种状态之一,并且可以通过
.then()
和.catch()
方法来处理异步操作的结果或错误。
Async/Await:
- 概念:Async/Await是建立在Promise之上的语法糖,使得异步代码看起来更像同步代码。
async function async1() {console.log('async1 start')await async2()console.log('async1 end')
}
async function async2() {console.log('async2')
}
console.log('script start')
async1()
console.log('script end')
思路
console.log('script start')
:立即在主线程中执行,打印出"script start"。async1()
:调用async1
函数,进入async1
函数内部执行。console.log('async1 start')
:立即在主线程中执行,打印出"async1 start"。await async2()
:使用await
关键字等待async2
函数执行完成。此时,主线程会暂时离开async1
函数,执行async2
函数。console.log('async2')
:立即在主线程中执行,打印出"async2"。
- 回到
async1
函数内部。 console.log('async1 end')
:立即在主线程中执行,打印出"async1 end"。
console.log('script end')
:立即在主线程中执行,打印出"script end"。
根据代码执行的顺序和await
关键字的特性,输出顺序应该是:script start -> async1 start -> async2 -> script end -> async1 end。
需要注意的
await
关键字会使主线程暂时离开async1
函数,执行async2
函数,直到async2
函数执行完成后再回到async1
函数继续执行后续代码。await
关键字后面的表达式应该是一个返回Promise对象的表达式,它会暂停async1
函数的执行,直到这个Promise对象状态变为resolved或rejected。await
关键字只能在async
函数内部使用。
// 使用Async/Await重写Promise的案例,使得异步操作更加直观// 模拟异步操作,返回一个Promise对象
function loadData() {return new Promise((resolve, reject) => {// 模拟异步操作,比如从服务器获取数据setTimeout(() => {const data = 'Simulated data loaded'resolve(data) // 异步操作成功,将数据传递给resolve}, 2000)})
}// 使用Async/Await重写Promise的案例
async function fetchData() {try {console.log('Start fetching data') // 同步操作const data = await loadData() // 等待异步操作完成console.log(data) // 在异步操作成功后输出数据console.log('Data fetched successfully') // 异步操作成功后的操作} catch (error) {console.error('Error:', error) // 捕获可能出现的错误}
}// 调用使用Async/Await重写的异步函数
fetchData()
在这个案例中,fetchData
函数使用了async
关键字声明,内部使用await
等待loadData
函数返回的Promise对象。当调用fetchData
时,它会立即执行,并在遇到await
关键字时暂停执行,直到loadData
函数返回的Promise状态变为resolved。这样使得异步代码看起来更像同步代码,易于理解和维护。
Async关键字声明的函数内部可以使用Await关键字等待Promise对象的解决,从而让异步代码更加清晰易懂。
- 需要注意:需要注意的是,使用Async/Await可以让异步代码看起来更像同步代码,避免了嵌套过深的回调函数或者过多的Promise链式调用。
await
关键字用于等待一个异步操作的完成,并暂停async
函数的执行,直到这个异步操作返回一个Promise对象。通过在await
后面的表达式中调用一个返回Promise的函数,可以实现同步的效果。在await
等待的过程中,JavaScript引擎可以继续执行其他任务,从而充分利用了线程资源。
需要注意的是,await
关键字只能在async
函数内部使用,并且只能等待返回Promise对象的表达式。在await
后面的代码将在等待的异步操作完成后继续执行。
总结
- setTimeout用于简单的延迟操作,但不适合复杂的异步操作处理。
- Promise提供了更结构化和灵活的异步操作处理方式,支持链式调用,能够更好地管理异步操作的状态和结果。
- Async/Await建立在Promise之上,使得异步代码更像同步代码,更易于理解和维护。
以上三种方式各有优劣,根据具体场景选择合适的方式来处理异步操作非常重要。
持续学习总结记录中,回顾一下上面的内容:
- setTimeout用于简单的延迟操作,但不适合复杂的异步操作处理。
- Promise提供了更结构化和灵活的异步操作处理方式,支持链式调用,能够更好地管理异步操作的状态和结果。
- Async/Await建立在Promise之上,使得异步代码更像同步代码,更易于理解和维护。
以上三种方式各有优劣,根据具体场景选择合适的方式来处理异步操作非常重要。