javascript异步理解

javascript是单线程编程,意思就是javascript引擎一次只能执行一个语句。这样在出现长时间的请求的话,会阻塞主线程,为了不阻塞主线程,出现了javascript异步的概念。

javascript 同步异步理解:
设想这样的情景,你现在路过一个炸鸡店,闻着特别香,你实在抵挡不住炸鸡的诱惑,你就走上前,买了一份炸鸡。
同步的情况是:你点了一份炸鸡,然后你站到跟前等着啥也不干,炸鸡好了之后,你付钱给老板。
异步的情况是:你点了一份炸鸡,然后老板给你一张号码单,你把钱付了,玩着手机等,炸鸡好了之后,老板再叫你。

同步代码:

const makeChicken = () => {
  console.log('炸鸡好了')
}
console.log('我要吃炸鸡')
makeChicken()
console.log('给你炸鸡钱')
console.log('玩手机')

执行结果:

我要吃炸鸡
炸鸡好了
给你炸鸡钱
玩手机

异步代码:

const makeChicken = () => {
  setTimeout(() => {
    console.log('炸鸡好了')
  }, 2000)
}
console.log('我要吃炸鸡')
makeChicken()
console.log('给你炸鸡钱')
console.log('玩手机')

执行结果:

我要吃炸鸡
给你炸鸡钱
玩手机
炸鸡好了

异步实现逻辑:


image.png

事件循环、web APIs 和消息队列不是JavaScript引擎的一部分,它们是浏览器端的JavaScript运行环境或者Nodejs端的JavaScript运行环境的一部分。在Nodejs中,web APIs被C/C++ APIs替代。

当上面的代码加载在浏览器中,console.log('我要吃炸鸡'),被推到栈中然后当结束时从栈中被移除。然后,makeChicken()触发,然后它被推到了栈的顶部。

接下来setTimeOut( )函数被调用,所以它被推到了栈顶。setTimeOut( )有两个参数:一是回调,二是毫秒数。

这个setTimeOut( )方法在web APIs环境中开始了一个2秒的计时器。此时,setTimeOut( )执行完毕并被移出栈。之后,console.log('给你炸鸡钱'),被推到栈里,执行完后被移除。

同时,计时器到期了,现在这个回调被推到了消息队列。但是这回调不会被立即执行,这里就是事件循环插手的地方。

事件循环的作用是查看调用栈并确定调用栈是否为空。 如果调用栈为空,它会查看消息队列以查看是否有任何挂起的回调等待执行。

在上面的例子中,消息队列中有一个回调,并且此时调用栈已经空了。 因此,事件循环将回调推到栈顶部。

之后, console.log('炸鸡好了')被推到栈顶部,执行完后从堆栈中弹出。 此时,回调已执行完毕,因此被从栈中移除,程序最终完成。

异步的几种实现:
1)回调函数:
意思就是等到炸鸡好了再叫你。

function getYourFood() {
  console.log('给你炸鸡')
}

function getChicken(callback) {
  console.log('准备制作炸鸡')
  setTimeout(() => {
    console.log('炸鸡制作完成')
    callback()
  }, 2000)
}

getChicken(getYourFood)

执行结果:

我要炸鸡
准备制作炸鸡
炸鸡制作完成
给你炸鸡

2)promise
使我们可以主动的去执行后面的动作,而不是把回调函数给一个方法等在这个方法内部调用。

function makeChicken() {
  return new Promise(((resolve) => {
    console.log('准备制作炸鸡')
    setTimeout(() => {
      resolve('炸鸡成功')
      console.log('炸鸡制作完成')
    }, 2000)
    console.log('炸鸡制作中')
  }))
}
function getYourFood() {
  return new Promise(((resolve) => {
    resolve('炸鸡好了')
  }))
}
console.log('我要炸鸡')
makeChicken().then(() => {
  getYourFood().then((seccess) => {
    console.log(seccess)
  })
})

执行结果:

我要炸鸡
准备制作炸鸡
炸鸡制作中
炸鸡制作完成
炸鸡好了

3)async await
使异步代码看起来就是同步代码。我们添加一个关键字async让引擎知道哪个函数触发是异步的并且会返回一个promise,让我们使用await。

function makeChicken() {
  return new Promise(((resolve) => {
    console.log('准备制作炸鸡')
    setTimeout(() => {
      resolve('炸鸡成功')
      console.log('炸鸡制作完成')
    }, 2000)
    console.log('炸鸡制作中')
  }))
}
function getYourFood() {
  return new Promise(((resolve) => {
    resolve('炸鸡好了')
  }))
}
async function OrderChicken() {
  await makeChicken()
  const result = await getYourFood()
  console.log(result)
}
console.log('我要炸鸡')
OrderChicken()

运行结果:

我要炸鸡
准备制作炸鸡
炸鸡制作中
炸鸡制作完成
炸鸡好了

我觉得下面链接的有关异步的讲解特别好。

参考链接:
[译]理解异步JavaScript-事件循环https://mbd.baidu.com/newspage/data/landingshare?pageType=1&isBdboxFrom=1&context=%7B%22nid%22%3A%22news_9071904341435333508%22%2C%22sourceFrom%22%3A%22bjh%22%7D

[翻译]JavaScript异步进化史:Callbacks,Promises,Async/Await 上
https://mbd.baidu.com/newspage/data/landingshare?context=%7B%22nid%22%3A%22news_8754335365643315921%22%2C%22sourceFrom%22%3A%22bjh%22%7D&type=news

[翻译]JavaScript异步进化史之下篇
https://mbd.baidu.com/newspage/data/landingshare?context=%7B%22nid%22%3A%22news_9356479249406614478%22%2C%22sourceFrom%22%3A%22bjh%22%7D&type=news

你可能感兴趣的:(javascript异步理解)