Javascript异步编程之一异步原理
生活随笔
收集整理的這篇文章主要介紹了
Javascript异步编程之一异步原理
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本系列的例子主要針對node.js環(huán)境,但瀏覽器端的原理應(yīng)該也是類似的。
本人也是Javascript新手,把自己這段時(shí)間學(xué)習(xí)積累的要點(diǎn)總結(jié)下來,希望可以對同樣在學(xué)習(xí)Javascript/node.js的同學(xué)有一些參考價(jià)值。盡量用通俗的語言幫助大家理解,如果有描述或理解不準(zhǔn)確的地方歡迎大家指正,交流。另外本文假定你已經(jīng)對javascript的語法和異步有一些基本的概念。 本系列會(huì)按一般學(xué)習(xí)異步編程的順序,首先介紹一下異步的原理,然后介紹各種異步編程的方法,從回調(diào)函數(shù)開始,然后慢慢進(jìn)入Promise和Generator等對異步編程體驗(yàn)進(jìn)行改進(jìn)的技術(shù)。期間也會(huì)大概提一下事件監(jiān)聽方式的異步調(diào)用,但是因?yàn)樘嗟氖录O(jiān)聽會(huì)讓程序流程變的不清晰,所以不太推薦(其實(shí)事件模式本質(zhì)上也是回調(diào)函數(shù))。Promise和Generator才是到目前為止(ES6),最好的異步編程方式。后面也會(huì)分享一下自己所理解的這兩種方式的對比(網(wǎng)上也有很多爭論)。ES7提出了更好的改進(jìn)方案,希望很快可以抽出時(shí)間研究一下,這是后話:) 好,進(jìn)入本節(jié)的正文。 什么是異步?同步異步與阻塞非阻塞有什么關(guān)系? ? node.js的“一切皆異步”的思想很有創(chuàng)意,目的是可以讓開發(fā)者輕松編寫高性能的web服務(wù)端,而不會(huì)“不小心”就用同步api阻塞了服務(wù)器從而影響性能。其他的語言比如php, python, java等基于同步的語言,雖然也有異步api,但畢竟編程人員的“思想上是同步的”,有時(shí)候不可避免的會(huì)寫出阻塞的代碼,node.js的目標(biāo)是造就“思想上是完全異步”的編程人員和編程語言:) 異步跟同步最大的不同就是異步api或函數(shù)被“調(diào)用”后不會(huì)等它運(yùn)行結(jié)束再執(zhí)行它后面的代碼,而是調(diào)用之后直接往下執(zhí)行,異步函數(shù)的“執(zhí)行”實(shí)際上是放在“其他地方”,待“執(zhí)行”完成后再把結(jié)果通過回調(diào)函數(shù)來進(jìn)行進(jìn)一步的使用或處理(所以異步函數(shù)書寫的時(shí)候不要用"return"來返回值哦,必須通過回調(diào)函數(shù)來返回值)。這里為什么強(qiáng)調(diào)“調(diào)用”和“執(zhí)行”兩個(gè)詞呢?就是為了更好的理解異步的過程。 打個(gè)比喻,你的領(lǐng)導(dǎo)要做個(gè)電子報(bào)表,笨領(lǐng)導(dǎo)的做法是,在自己電腦上把該統(tǒng)計(jì)的統(tǒng)計(jì)了,該算的算了,最后生成一張報(bào)表,然后用這個(gè)報(bào)表做接下去的工作;聰明的領(lǐng)導(dǎo),會(huì)發(fā)個(gè)郵件給下屬,把報(bào)表的要求寫清楚,下屬在自己的電腦上把報(bào)表做完后,發(fā)個(gè)郵件把報(bào)表交回給領(lǐng)導(dǎo)。在下屬做報(bào)表的時(shí)候,領(lǐng)導(dǎo)可以在自己電腦上繼續(xù)做其他事情,比如玩游戲、看視頻等等(你懂的)。 在上面這個(gè)例子中,領(lǐng)導(dǎo)是編程者(你),領(lǐng)導(dǎo)的電腦是當(dāng)前線程,下屬的電腦是另一個(gè)線程(如果有多個(gè)下屬就相當(dāng)于有個(gè)線程池)。做報(bào)表這件工作是個(gè)異步函數(shù),發(fā)郵件給下屬相當(dāng)于調(diào)用這個(gè)函數(shù),下屬電腦上做報(bào)表相當(dāng)于在另一個(gè)線程異步執(zhí)行這個(gè)函數(shù),執(zhí)行完了發(fā)郵件把報(bào)表發(fā)回給領(lǐng)導(dǎo)相當(dāng)于調(diào)用回調(diào)函數(shù),領(lǐng)導(dǎo)就可以使用這個(gè)報(bào)表接著做下面的工作(相當(dāng)于回掉函數(shù)里面的代碼)。下屬做報(bào)表的時(shí)候領(lǐng)導(dǎo)完全不用管而是可以繼續(xù)干其他事情。 通過這個(gè)例子可以清楚的看到,領(lǐng)導(dǎo)只能在他自己的電腦(用戶線程)上工作,異步的函數(shù)都是在下屬的電腦上(異步線程)做的。這一點(diǎn)在很多文章當(dāng)中并沒有講的很清楚,所以容易造成困擾,因?yàn)楹芏嗳酥皇且晃兜膹?qiáng)調(diào)javascript是單線程的,但單線程怎么能實(shí)現(xiàn)異步呢?就并沒有講清楚。其實(shí)所謂的單線程是指用戶線程是單線程,而另外還有一個(gè)或多個(gè)線程處理異步代碼的執(zhí)行。 接下來再說說阻塞的問題。很多文章里面在講解的時(shí)候同步異步阻塞非阻塞混為一團(tuán),新手很難理解,最容易產(chǎn)生的誤解就是同步=阻塞,異步=非阻塞。其實(shí)阻塞非阻塞跟同步異步?jīng)]有任何關(guān)系。簡單講,阻塞就是一個(gè)api或者函數(shù)運(yùn)行時(shí)間過長,而獨(dú)占cpu導(dǎo)致其他代碼不能運(yùn)行,那么多長時(shí)間算阻塞呢?相信這只是一個(gè)相對的概念,只要明顯影響到程序的性能和用戶體驗(yàn),就算阻塞吧。那跟同步異步是什么關(guān)系呢?阻塞的代碼如果同步執(zhí)行就會(huì)阻塞到自己后面代碼的運(yùn)行,所以自然而然的就想到異步來執(zhí)行阻塞的代碼,然而異步真能解決阻塞問題嗎?下面繼續(xù)講。 node.js里面的異步 大家知道Javascript的基本語法跟其他編程語言大同小異,最大的不同就是把異步擺在首位,特別是node.js更是大部分api都是異步的,小量同步api。這與其他大部分語言剛好相反,也給習(xí)慣于同步編程思維的同學(xué)造成了很大的困擾,就是常說的轉(zhuǎn)不過彎來,習(xí)慣性的認(rèn)為代碼是按順序一行一行的往下執(zhí)行。 上面介紹了異步非阻塞的概念,那么具體到node.js是怎么實(shí)現(xiàn)的呢?這里又會(huì)涉及到I/O的概念,具體不講I/O的細(xì)節(jié)(操作系統(tǒng)原理都會(huì)講),關(guān)鍵就一點(diǎn),I/O操作通常比較耗時(shí)但不會(huì)獨(dú)占CPU,典型的I/O比如文件讀寫,遠(yuǎn)程數(shù)據(jù)庫讀寫,網(wǎng)絡(luò)請求等。 先講耗時(shí),如果用同步API來進(jìn)行I/O操作,在返回結(jié)果之前就只能等待,所以最好的辦法上面已經(jīng)講過,就是進(jìn)行異步操作。接著說一下不會(huì)霸占CPU的好處。在node.js進(jìn)程里面,有一個(gè)用戶線程(javascript所宣稱的單線程)和一個(gè)異步線程池(用戶無法直接訪問), 如果跑在異步線程上的代碼是阻塞的,那么這種異步根本就起不到消除阻塞的作用,為什么?原因就是阻塞代碼會(huì)霸占cpu,導(dǎo)致本進(jìn)程所有代碼都等待不管是哪個(gè)線程。但是,,,剛剛講的node.js里面的I/O API都是不會(huì)霸占CPU的,所以是非阻塞的,就不會(huì)出現(xiàn)這個(gè)問題。這就是node.js的最引以為傲的特性之一:異步非阻塞I/O. 上面只是強(qiáng)調(diào)異步非阻塞,那么對于真正的阻塞代碼,node.js怎么辦呢?不好意思。。。單個(gè)node.js進(jìn)程真無能為力,跟同步編程語言相比沒什么優(yōu)勢,只能用傳統(tǒng)的方式,多進(jìn)程,多開幾個(gè)node.js進(jìn)程,甚至多開幾個(gè)服務(wù)器。任何語言都有它的強(qiáng)項(xiàng)和弱項(xiàng),node.js的強(qiáng)項(xiàng)就是它本來的設(shè)計(jì)初衷:讓開發(fā)者能夠輕松的編寫高性能的web服務(wù)器(進(jìn)行的最多的就是網(wǎng)絡(luò)和數(shù)據(jù)庫的I/O操作),而不是做大量的CPU密集型的運(yùn)算(不過我趕腳,就算要做很多阻塞操作,用多進(jìn)程和多服務(wù)器又有何不可?node.js對此提供了足夠的支持)。這樣算是回答了上一小節(jié)最后的問題了吧:) 要理解javascript異步編程和其他語言同步編程的區(qū)別,可以從一個(gè)最簡單的例子開始。在同步為主的語言中,如果需要等待10秒鐘,通常是類似sleep 10之類的語句,在10秒之內(nèi)整個(gè)進(jìn)程掛起,也就是阻塞10秒。但javascript不是這樣,它是使用setTimeout函數(shù),從字面意思就已經(jīng)可以看出區(qū)別了, 設(shè)一個(gè)timeout的時(shí)間, 在這段時(shí)間內(nèi)cpu可以繼續(xù)運(yùn)行其他代碼, 等10秒時(shí)間到了, 就用回調(diào)函數(shù)的形式來做應(yīng)該10秒之后才做的事情。 到此,這一節(jié)異步編程的原理大概就概括了一下,在進(jìn)一步深入學(xué)習(xí)異步編程之前一定要理解的概念。以上都是自己的理解,錯(cuò)誤或不準(zhǔn)確的地方還望不吝賜教:) 下一節(jié)會(huì)介紹最基礎(chǔ)的javascript的異步編程方式:回調(diào)函數(shù),所有其他方式都是基于它的改進(jìn)。 附注:也許是我讀得書少:) 這么久以來沒有發(fā)現(xiàn)網(wǎng)上有對異步編程講解的很透徹的文章,在自己學(xué)習(xí)過的資料當(dāng)中,樸靈的《深入淺出node.js》是講解的最深入透徹的,強(qiáng)烈推薦。 轉(zhuǎn)載請標(biāo)明出處: http://www.cnblogs.com/chrischjh/p/4648395.html
轉(zhuǎn)載于:https://www.cnblogs.com/chrischjh/p/4648395.html
總結(jié)
以上是生活随笔為你收集整理的Javascript异步编程之一异步原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 两金压控的两金是什么
- 下一篇: Javascript简介