工程笔记

复习面试题 - 打印题 - Promise 执行顺序

本篇目录

import { CodeSandbox } from '@/components/CodeSandbox'

复习面试题 - 打印题 - Promise 执行顺序

题目 1:async/await

解释:await fn,这个fn仍然是同步,但是 await fn后面的成了微任务,所以会先打印 async1 end

import { useState } from 'react'

export default function AsyncAwaitDemo() {
  const [logs, setLogs] = useState([])

  function log(msg) {
    setLogs((prev) => [...prev, msg])
  }

  async function async1() {
    log('async1 start')
    await async2()
    log('async1 end')
  }
  async function async2() {
    log('async2')
  }

  function handleClick() {
    setLogs([])
    log('script start')
    setTimeout(() => log('setTimeout'), 0)
    async1()
    new Promise((resolve) => {
      log('promise1')
      resolve()
    }).then(() => {
      log('promise2')
    })
    log('script end')
  }

  return (
    <div>
      <button onClick={handleClick}>执行 async/await 顺序</button>
      <div>输出:</div>
      <pre>{logs.join('\n')}</pre>
    </div>
  )
}

题目 2:resolve

解释:resolve 不会阻止当前的同步执行,所以先打印3,4,执行完了同步再执行resolve,两个setTimeout,一个0,一个10,所以先打印6,2

import { useState } from 'react'

export default function ResolveDemo() {
  const [logs, setLogs] = useState([])
  function log(msg) {
    setLogs((prev) => [...prev, msg])
  }
  function handleClick() {
    setLogs([])
    log('1')
    setTimeout(() => log('2'), 10)
    new Promise((resolve) => {
      log('3')
      resolve()
      log('4')
    }).then(() => log('5'))
    setTimeout(() => log('6'), 0)
    log('7')
  }
  return (
    <div>
      <button onClick={handleClick}>执行 resolve 顺序</button>
      <div>输出:</div>
      <pre>{logs.join('\n')}</pre>
    </div>
  )
}

题目 3:Promise链式调用

import { useState } from 'react'

export default function PromiseDemo() {
  const [result, setResult] = useState('')

  function testPromiseChain() {
    setResult('执行中...')
    const results = []

    results.push('1. 开始执行')

    Promise.resolve()
      .then(() => {
        results.push('2. 第一个then')
        return Promise.resolve()
      })
      .then(() => {
        results.push('3. 第二个then')
        // return Promise.resolve()
      })
      .then(() => {
        results.push('4. 第三个then')
        updateResult()
      })

    Promise.resolve().then(() => {
      results.push('5. 独立的Promise')
      updateResult()
    })

    results.push('6. 同步代码结束')

    function updateResult() {
      setResult(results.join('\n') + '\n\n解释:微任务按照加入队列的顺序执行')
    }

    setTimeout(updateResult, 10)
  }

  return (
    <div>
      <button onClick={testPromiseChain}>测试Promise链</button>
      <pre>结果:{result}</pre>
    </div>
  )
}

题目 4:then

解释:多个 then 都会执行

import { useState } from 'react'

export default function ThenDemo() {
  const [logs, setLogs] = useState([])
  function log(msg) {
    setLogs((prev) => [...prev, msg])
  }
  async function async1() {
    log('async1 start')
    await async2()
    log('async1 middle')
    await async3()
    log('async1 end')
  }
  async function async2() {
    log('async2')
  }
  async function async3() {
    log('async3')
  }
  function handleClick() {
    setLogs([])
    log('script start')
    setTimeout(() => log('setTimeout'), 0)
    async1()
    new Promise((resolve) => {
      log('promise1')
      resolve(1)
    })
      .then((res) => {
        log('promise2 ' + res)
        return Promise.resolve(2)
      })
      .then((res) => {
        log('promise3 ' + res)
      })
    log('script end')
  }
  return (
    <div>
      <button onClick={handleClick}>执行 then 顺序</button>
      <div>输出:</div>
      <pre>{logs.join('\n')}</pre>
    </div>
  )
}

题目 5:Promise.all

解释:promise.all 会等待所有 promise 都执行完,然后执行 then

import { useState } from 'react'

export default function PromiseAllDemo() {
  const [logs, setLogs] = useState([])
  function log(msg) {
    setLogs((prev) => [...prev, msg])
  }
  function handleClick() {
    setLogs([])
    log('start')
    Promise.all([
      new Promise((resolve) => {
        setTimeout(() => {
          log('promise1')
          resolve(1)
        }, 2000)
      }),
      new Promise((resolve) => {
        setTimeout(() => {
          log('promise2')
          resolve(2)
        }, 1000)
      })
    ]).then((res) => {
      log('all done ' + JSON.stringify(res))
    })
    log('end')
  }
  return (
    <div>
      <button onClick={handleClick}>执行 Promise.all 顺序</button>
      <div>输出:</div>
      <pre>{logs.join('\n')}</pre>
    </div>
  )
}

题目 6:事件循环

解释:清空完微任务再执行宏任务

import { useState } from 'react'

export default function EventLoopDemo() {
  const [logs, setLogs] = useState([])
  function log(msg) {
    setLogs((prev) => [...prev, msg])
  }
  function handleClick() {
    setLogs([])
    log('1')
    setTimeout(() => {
      log('2')
      Promise.resolve().then(() => log('3'))
    }, 0)
    new Promise((resolve) => {
      log('4')
      resolve()
    }).then(() => {
      log('5')
      setTimeout(() => log('6'), 0)
    })
    Promise.resolve().then(() => log('7'))
    log('8')
  }
  return (
    <div>
      <button onClick={handleClick}>执行事件循环顺序</button>
      <div>输出:</div>
      <pre>{logs.join('\n')}</pre>
    </div>
  )
}

总结

  • await 会暂停 async 函数执行,await 之后的代码会作为微任务加入队列
  • resolve 不会影响同步执行
  • then 都会执行,默认是 return undefined
  • 事件循环,先清空微任务,再执行宏任务