真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

同步JavaScript是如何工作的

這篇文章主要介紹同步JavaScript是如何工作的,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

在中站等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站建設(shè)、成都網(wǎng)站制作 網(wǎng)站設(shè)計(jì)制作按需求定制設(shè)計(jì),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),成都全網(wǎng)營(yíng)銷推廣,成都外貿(mào)網(wǎng)站制作,中站網(wǎng)站建設(shè)費(fèi)用合理。

JavsScript 是一門單線程的編程語(yǔ)言,這就意味著一個(gè)時(shí)間里只能處理一件事,也就是說 JavaScript 引擎一次只能在一個(gè)線程里處理一條語(yǔ)句。

雖然單線程簡(jiǎn)化了編程代碼,因?yàn)槟悴槐靥珦?dān)心并發(fā)引出的問題,這也意味著你將在阻塞主線程的情況下執(zhí)行長(zhǎng)時(shí)間的操作,如網(wǎng)絡(luò)請(qǐng)求。

想象一下從API請(qǐng)求一些數(shù)據(jù),根據(jù)具體的情況,服務(wù)器需要一些時(shí)間來(lái)處理請(qǐng)求,同時(shí)阻塞主線程,使網(wǎng)頁(yè)長(zhǎng)時(shí)間處于無(wú)響應(yīng)的狀態(tài)。

這就是引入異步 JavaScript 的原因。使用異步 JavaScript(如 回調(diào)函數(shù)、promise、async/await),可以不用阻塞主線程的情況下長(zhǎng)時(shí)間執(zhí)行網(wǎng)絡(luò)請(qǐng)求 :)

可能你知道不知道 異步 JavsScript 是如何工作,并不要緊,但知道它是如何工作,對(duì) JavaScript 異步更深入的了解是有幫助的。

所以不在啰嗦了,我們開始吧 :)

同步JavaScript是如何工作的?

在深入研究異步JavaScript之前,讓我們首先了解同步 JavaScript 代碼如何在 JavaScript 引擎中執(zhí)行。例如:

    const second = () => {
      console.log('Hello there!');
    }
    
    const first = () => {
      console.log('Hi there!');
      second();
      console.log('The End');
    }
    
    first();

要理解上述代碼如何在 JavaScript 引擎中執(zhí)行,我們必須理解執(zhí)行上下文和調(diào)用堆棧(也稱為執(zhí)行堆棧)的概念。

函數(shù)代碼在函數(shù)執(zhí)行上下文中執(zhí)行,全局代碼在全局執(zhí)行上下文中執(zhí)行。每個(gè)函數(shù)都有自己的執(zhí)行上下文。

調(diào)用棧

調(diào)用堆棧顧名思義是一個(gè)具有LIFO(后進(jìn)先出)結(jié)構(gòu)的堆棧,用于存儲(chǔ)在代碼執(zhí)行期間創(chuàng)建的所有執(zhí)行上下文。

JavaScript 只有一個(gè)調(diào)用棧,因?yàn)樗且环N單線程編程語(yǔ)言。調(diào)用堆棧具有 LIFO 結(jié)構(gòu),這意味著項(xiàng)目只能從堆棧頂部添加或刪除。

讓我們回到上面的代碼片段,并嘗試?yán)斫獯a如何在JavaScript引擎中執(zhí)行。

const second = () => {
  console.log('Hello there!');
}
const first = () => {
  console.log('Hi there!');
  second();
  console.log('The End');
}
first();

同步JavaScript是如何工作的

這里發(fā)生了什么?

當(dāng)執(zhí)行此代碼時(shí),將創(chuàng)建一個(gè)全局執(zhí)行上下文(由main()表示)并將其推到調(diào)用堆棧的頂部。當(dāng)遇到對(duì)first()的調(diào)用時(shí),它會(huì)被推送到堆棧的頂部。

接下來(lái),console.log('Hi there!')被推送到堆棧的頂部,當(dāng)它完成時(shí),它會(huì)從堆棧中彈出。之后,我們調(diào)用second(),因此second()函數(shù)被推到堆棧的頂部。

console.log('Hello there!')被推送到堆棧頂部,并在完成時(shí)彈出堆棧。second() 函數(shù)結(jié)束,因此它從堆棧中彈出。

console.log(“the End”)被推到堆棧的頂部,并在完成時(shí)刪除。之后,first()函數(shù)完成,因此從堆棧中刪除它。

程序在這一點(diǎn)上完成了它的執(zhí)行,所以全局執(zhí)行上下文(main())從堆棧中彈出。

異步JavaScript是如何工作的?

現(xiàn)在我們已經(jīng)對(duì)調(diào)用堆棧和同步JavaScript的工作原理有了基本的了解,讓我們回到異步JavaScript。

阻塞是什么?

讓我們假設(shè)我們正在以同步的方式進(jìn)行圖像處理或網(wǎng)絡(luò)請(qǐng)求。例如:

const processImage = (image) => {
  /**
  * doing some operations on image
  **/
  console.log('Image processed');
}
const networkRequest = (url) => {
  /**
  * requesting network resource
  **/
  return someData;
}
const greeting = () => {
  console.log('Hello World');
}
processImage(logo.jpg);
networkRequest('www.somerandomurl.com');
greeting();

做圖像處理和網(wǎng)絡(luò)請(qǐng)求需要時(shí)間,當(dāng)processImage()函數(shù)被調(diào)用時(shí),它會(huì)根據(jù)圖像的大小花費(fèi)一些時(shí)間。

processImage() 函數(shù)完成后,將從堆棧中刪除它。然后調(diào)用 networkRequest() 函數(shù)并將其推入堆棧。同樣,它也需要一些時(shí)間來(lái)完成執(zhí)行。

最后,當(dāng)networkRequest()函數(shù)完成時(shí),調(diào)用greeting()函數(shù),因?yàn)樗话粋€(gè)控制臺(tái)。日志語(yǔ)句和控制臺(tái)。日志語(yǔ)句通常很快,因此greeting()函數(shù)立即執(zhí)行并返回。

因此,我們必須等待函數(shù)(如processImage()或networkRequest())完成。這意味著這些函數(shù)阻塞了調(diào)用堆棧或主線程。因此,在執(zhí)行上述代碼時(shí),我們不能執(zhí)行任何其他操作,這是不理想的。

那么解決辦法是什么呢?

最簡(jiǎn)單的解決方案是異步回調(diào)。我們使用異步回調(diào)使代碼非阻塞。例如:

const networkRequest = () => {
  setTimeout(() => {
    console.log('Async Code');
  }, 2000);
};
console.log('Hello World');
networkRequest();

這里我使用了setTimeout方法來(lái)模擬網(wǎng)絡(luò)請(qǐng)求。請(qǐng)記住setTimeout不是JavaScript引擎的一部分,它是web api(在瀏覽器中)和C/ c++ api(在node.js中)的一部分。

為了理解這段代碼是如何執(zhí)行的,我們必須理解更多的概念,比如事件輪詢和回調(diào)隊(duì)列(或消息隊(duì)列)。

同步JavaScript是如何工作的

事件輪詢、web api和消息隊(duì)列不是JavaScript引擎的一部分,而是瀏覽器的JavaScript運(yùn)行時(shí)環(huán)境或Nodejs JavaScript運(yùn)行時(shí)環(huán)境的一部分(對(duì)于Nodejs)。在Nodejs中,web api被c/c++ api所替代。

現(xiàn)在讓我們回到上面的代碼,看看它是如何異步執(zhí)行的。

const networkRequest = () => {
  setTimeout(() => {
    console.log('Async Code');
  }, 2000);
};

console.log('Hello World');

networkRequest();

console.log('The End');

同步JavaScript是如何工作的

當(dāng)上述代碼在瀏覽器中加載時(shí),console.log(' Hello World ') 被推送到堆棧中,并在完成后彈出堆棧。接下來(lái),將遇到對(duì) networkRequest() 的調(diào)用,因此將它推到堆棧的頂部。

下一個(gè) setTimeout() 函數(shù)被調(diào)用,因此它被推到堆棧的頂部。setTimeout()有兩個(gè)參數(shù):

  • 1) 回調(diào)和

  • 2) 以毫秒(ms)為單位的時(shí)間。

setTimeout() 方法在web api環(huán)境中啟動(dòng)一個(gè)2s的計(jì)時(shí)器。此時(shí),setTimeout()已經(jīng)完成,并從堆棧中彈出。cosole.log(“the end”) 被推送到堆棧中,在完成后執(zhí)行并從堆棧中刪除。

同時(shí),計(jì)時(shí)器已經(jīng)過期,現(xiàn)在回調(diào)被推送到消息隊(duì)列。但是回調(diào)不會(huì)立即執(zhí)行,這就是事件輪詢開始的地方。

事件輪詢

事件輪詢的工作是監(jiān)聽調(diào)用堆棧,并確定調(diào)用堆棧是否為空。如果調(diào)用堆棧是空的,它將檢查消息隊(duì)列,看看是否有任何掛起的回調(diào)等待執(zhí)行。

在這種情況下,消息隊(duì)列包含一個(gè)回調(diào),此時(shí)調(diào)用堆棧為空。因此,事件輪詢將回調(diào)推到堆棧的頂部。

然后是 console.log(“Async Code”) 被推送到堆棧頂部,執(zhí)行并從堆棧中彈出。此時(shí),回調(diào)已經(jīng)完成,因此從堆棧中刪除它,程序最終完成。

消息隊(duì)列還包含來(lái)自DOM事件(如單擊事件和鍵盤事件)的回調(diào)。例如:

document.querySelector('.btn').addEventListener('click',(event) => {
  console.log('Button Clicked');
});

對(duì)于DOM事件,事件偵聽器位于web api環(huán)境中,等待某個(gè)事件(在本例中單擊event)發(fā)生,當(dāng)該事件發(fā)生時(shí),回調(diào)函數(shù)被放置在等待執(zhí)行的消息隊(duì)列中。

同樣,事件輪詢檢查調(diào)用堆棧是否為空,并在調(diào)用堆棧為空并執(zhí)行回調(diào)時(shí)將事件回調(diào)推送到堆棧。

延遲函數(shù)執(zhí)行

我們還可以使用setTimeout來(lái)延遲函數(shù)的執(zhí)行,直到堆棧清空為止。例如

const bar = () => {
  console.log('bar');
}
const baz = () => {
  console.log('baz');
}
const foo = () => {
  console.log('foo');
  setTimeout(bar, 0);
  baz();
}
foo();

打印結(jié)果:

foo
baz
bar

當(dāng)這段代碼運(yùn)行時(shí),第一個(gè)函數(shù)foo()被調(diào)用,在foo內(nèi)部我們調(diào)用console.log('foo'),然后setTimeout()被調(diào)用,bar()作為回調(diào)函數(shù)和時(shí)0秒計(jì)時(shí)器。

現(xiàn)在,如果我們沒有使用 setTimeout, bar() 函數(shù)將立即執(zhí)行,但是使用 setTimeout 和0秒計(jì)時(shí)器,將bar的執(zhí)行延遲到堆棧為空的時(shí)候。

0秒后,bar()回調(diào)被放入等待執(zhí)行的消息隊(duì)列中。但是它只會(huì)在堆棧完全空的時(shí)候執(zhí)行,也就是在baz和foo函數(shù)完成之后。

ES6 任務(wù)隊(duì)列

我們已經(jīng)了解了異步回調(diào)和DOM事件是如何執(zhí)行的,它們使用消息隊(duì)列存儲(chǔ)等待執(zhí)行所有回調(diào)。

ES6引入了任務(wù)隊(duì)列的概念,任務(wù)隊(duì)列是 JavaScript 中的 promise 所使用的。消息隊(duì)列和任務(wù)隊(duì)列的區(qū)別在于,任務(wù)隊(duì)列的優(yōu)先級(jí)高于消息隊(duì)列,這意味著任務(wù)隊(duì)列中的promise 作業(yè)將在消息隊(duì)列中的回調(diào)之前執(zhí)行,例如:

const bar = () => {
  console.log('bar');
};

const baz = () => {
  console.log('baz');
};

const foo = () => {
  console.log('foo');
  setTimeout(bar, 0);
  new Promise((resolve, reject) => {
    resolve('Promise resolved');
  }).then(res => console.log(res))
    .catch(err => console.log(err));
  baz();
};

foo();

打印結(jié)果:

foo
baz
Promised resolved
bar

我們可以看到 promise 在 setTimeout 之前執(zhí)行,因?yàn)?promise 響應(yīng)存儲(chǔ)在任務(wù)隊(duì)列中,任務(wù)隊(duì)列的優(yōu)先級(jí)高于消息隊(duì)列。

以上是“同步JavaScript是如何工作的”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


名稱欄目:同步JavaScript是如何工作的
網(wǎng)址分享:http://weahome.cn/article/jihgpp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部