前端JavaScript篇之setTimeout、Promise、Async/Await 的区别

目录

  • 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

前端JavaScript篇之setTimeout、Promise、Async/Await 的区别_第1张图片

思路

  1. console.log('script start'):立即在主线程中执行,打印出"script start"。
  2. setTimeout(function(){ console.log('settimeout') }):调用setTimeout函数,并定义其完成后执行的回调函数,但没有指定延迟的时间。因此,回调函数将会被添加到任务队列中,等待主线程执行完毕后立即执行。
  3. 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') // 同步操作

前端JavaScript篇之setTimeout、Promise、Async/Await 的区别_第2张图片

在这个案例中,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')

前端JavaScript篇之setTimeout、Promise、Async/Await 的区别_第3张图片

思路

  1. console.log('script start'):立即在主线程中执行,打印出"script start"。
  2. let promise1 = new Promise(function (resolve) { ... }):创建一个新的Promise对象,立即执行传入的函数。在这个函数中:
    • console.log('promise1'):立即在主线程中执行,打印出"promise1"。
    • resolve():立即将Promise状态从pending变为fulfilled。
    • console.log('promise1 end'):立即在主线程中执行,打印出"promise1 end"。
  3. .then(function () { console.log('promise2') }):注册在Promise对象状态变为fulfilled后执行的回调函数,但是由于Promise状态已经是fulfilled,所以这个回调函数会被添加到微任务队列中,等待主线程执行完毕后立即执行。
  4. setTimeout(function(){ console.log('settimeout') }):调用setTimeout函数,并定义其完成后执行的回调函数,但没有指定延迟的时间。因此,回调函数会被添加到任务队列中,等待主线程执行完毕后立即执行。
  5. 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) // 捕获可能出现的错误
  })

前端JavaScript篇之setTimeout、Promise、Async/Await 的区别_第4张图片

在这个案例中,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')

前端JavaScript篇之setTimeout、Promise、Async/Await 的区别_第5张图片

思路

  1. console.log('script start'):立即在主线程中执行,打印出"script start"。
  2. 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"。
  3. 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()

前端JavaScript篇之setTimeout、Promise、Async/Await 的区别_第6张图片

在这个案例中,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之上,使得异步代码更像同步代码,更易于理解和维护。
    以上三种方式各有优劣,根据具体场景选择合适的方式来处理异步操作非常重要。

你可能感兴趣的:(JavaScript,前端知识点,前端,javascript,开发语言)