Javascript 異步編程(一)初識異步

關(guān)于同步和異步证舟,我們先來看兩個例子。

const async=()=>{
  console.log('async..',1)
  let t=new Date();
  while (true){
    if(+new Date()-t>=2000){
      console.log('async...',2)
      break
    }
  }
  console.log('async...',3)
}
async();
//async.. 1
//async... 2
//async... 3

順序執(zhí)行

const sync=()=>{
  console.log('sync...',1);
  setTimeout(()=>{
    console.log('sync...',2)
  },2000);
  console.log('sync...',3)
}
sync();
//sync... 1
//sync... 3
//sync... 2

可能都知道JavaScript是單線程的缺谴,即同一時刻只能做一件事但惶,如果有多個任務(wù),則需要排隊執(zhí)行湿蛔,但是這樣同步執(zhí)行的效率低膀曾,如果一個任務(wù)長時間據(jù)有CPU,其他任務(wù)則需要等待阳啥,這無疑會浪費(fèi)資源添谊,造成資源利用率低。為此苫纤,
JavaScript將任務(wù)的執(zhí)行分為兩種:

  • 同步:后一個任務(wù)等待前一個任務(wù)結(jié)束碉钠,然后再執(zhí)行纲缓,程序的執(zhí)行順序與任務(wù)的排列順序是一致的、同步的喊废;
  • 異步:后一個任務(wù)不等前一個任務(wù)結(jié)束就執(zhí)行祝高,程序的執(zhí)行順序與任務(wù)的排列順序是不一致的、異步的

需要了解的基本知識

進(jìn)程與線程

進(jìn)程(process):我們知道污筷,程序運(yùn)行是需要系統(tǒng)資源的(CPU,內(nèi)存工闺,I/O等)為了能使程序能夠并發(fā)執(zhí)行,并對并發(fā)執(zhí)行的程序加以描述和控制瓣蛀,從而引入進(jìn)程陆蟆。是進(jìn)程實體的運(yùn)行過程,是系統(tǒng)進(jìn)行資源分配和調(diào)動的獨(dú)立單位

線程(thread):通過引入線程惋增,一個能獨(dú)立運(yùn)行的基本單位叠殷,作為操作系統(tǒng)調(diào)度和分派的基本單位。通過減少程序在并發(fā)進(jìn)行時所付出的時空開銷诈皿,從而提高程序并發(fā)執(zhí)行的程度林束,以及提高資源利用率和系統(tǒng)的吞吐量

進(jìn)程和線程的區(qū)別和關(guān)系:

  • 進(jìn)程是操作系統(tǒng)分配資源的最小單位,線程是程序執(zhí)行的最小單位稽亏。
  • 一個進(jìn)程由一個或多個線程組成壶冒,線程是一個進(jìn)程中代碼的不同執(zhí)行路線;
  • 進(jìn)程之間相互獨(dú)立截歉,但同一進(jìn)程下的各個線程之間共享程序的內(nèi)存空間(包括代碼段胖腾、數(shù)據(jù)集、堆等)及一些進(jìn)程級的資源(如打開文件和信號)瘪松。
  • 調(diào)度和切換:線程上下文切換比進(jìn)程上下文切換要快得多咸作。

鏈接

以工廠模式比喻,江南皮革廠老板苦惱產(chǎn)量提不上去凉逛,于是給車間主任(進(jìn)程)開會性宏。
老板:你們幾個怎么搞得,怎么訂單(多任務(wù))多了状飞,產(chǎn)量還跟不上了毫胜?
車間主任A:手底下這么多人,哪管的過來诬辈。訂單不好分配酵使、進(jìn)度不無法跟蹤
車間主任B:A車間經(jīng)常跟我們車間搶物料(系統(tǒng)資源)
車間主任A:放***屁,你們的人上個月還搶我設(shè)備呢(系統(tǒng)資源)
老板:當(dāng)然你們說的都是客觀存在的因素焙糟,你們不會從手下挑選幾個有能力的人成立班組(線程)么口渔?權(quán)利下放(獨(dú)立調(diào)度)
車間主任A,B:好好好,試試穿撮。

linux下查看進(jìn)程的常用命令

  • ps
  • top

Javascript 單線程

ecma-262中并無與線程相關(guān)的內(nèi)容缺脉,其單線程/多線程主要依賴于其JavaScript引擎(解釋器)痪欲。

瀏覽器的進(jìn)程和線程

以Chrome為例,Chrome瀏覽器使用多個進(jìn)程來隔離不同的網(wǎng)頁攻礼。因此在Chrome中打開一個網(wǎng)頁相當(dāng)于起了一個進(jìn)程


image_2.png

多進(jìn)程的原因:

  1. 因為進(jìn)程之間相互獨(dú)立业踢,一個瀏覽器選項卡無響應(yīng)不會影響其他的選項卡。
  2. 同樣因為進(jìn)程之間相互獨(dú)立礁扮,一個選項卡中如果惡意腳本知举,不會影響其他選項卡。例如太伊,Chrome 瀏覽器可以對處理用戶輸入(如渲染器)的進(jìn)程雇锡,限制其文件訪問的權(quán)限。

GUI線程:渲染布局(HTML,CSS等)

JS引擎線程:1.解析僚焦、執(zhí)行JS 2.與GUI線程互斥 (因為引擎是單線程的锰提,所以Javascript是單線程的)

定時觸發(fā)器線程:setTimeout/setInterval

事件觸發(fā)線程:將滿足觸發(fā)條件的時間放入任務(wù)隊列

異步HTTP請求線程:XHR所在線程

單線程的原因(引用自瀏覽器進(jìn)程?線程芳悲?傻傻分不清楚欲账!
這是因為Javascript這門腳本語言誕生的使命所致:JavaScript為處理頁面中用戶的交互,以及操作DOM樹芭概、CSS樣式樹來給用戶呈現(xiàn)一份動態(tài)而豐富的交互體驗和服務(wù)器邏輯的交互處理。如果JavaScript是多線程的方式來操作這些UI DOM惩嘉,則可能出現(xiàn)UI操作的沖突罢洲; 如果Javascript是多線程的話,在多線程的交互下文黎,處于UI中的DOM節(jié)點就可能成為一個臨界資源惹苗,假設(shè)存在兩個線程同時操作一個DOM,一個負(fù)責(zé)修改一個負(fù)責(zé)刪除耸峭,那么這個時候就需要瀏覽器來裁決如何生效哪個線程的執(zhí)行結(jié)果桩蓉。當(dāng)然我們可以通過鎖來解決上面的問題。但為了避免因為引入了鎖而帶來更大的復(fù)雜性劳闹,Javascript在最初就選擇了單線程執(zhí)行院究。

Node.js中的進(jìn)程和線程

當(dāng)一個 Node.js 的應(yīng)用啟動的同時,它會啟動如下模塊:

  • 一個進(jìn)程
  • 一個線程:單線程意味著在當(dāng)前進(jìn)程中同一時刻只有一個指令在執(zhí)行本涕。
  • 事件循環(huán)機(jī)制:盡管 JavaScript 是單線程的业汰,但通過使用回調(diào),promises, async/await 等語法菩颖,基于事件循環(huán)將對操作系統(tǒng)的操作異步化样漆,使得 Node 擁有異步非阻塞 IO 的特性。
  • JS 引擎實例
  • Node.js 實例

Node 運(yùn)行在單線程上晦闰,并且在事件循環(huán)中同一時刻只有一個進(jìn)程的任務(wù)被執(zhí)行放祟,每次同一時刻只會執(zhí)行一段代碼(多段代碼不會同時執(zhí)行)鳍怨。
只有一個js引擎在主線程上運(yùn)行。其他異步IO和事件驅(qū)動相關(guān)的線程通過libuv來實現(xiàn)內(nèi)部的線程池和線程調(diào)度

為什么Node.js也是單線程呢跪妥?

因為JavaScript起初是運(yùn)行在瀏覽器端的...你懂的鞋喇。

Node.js如何實現(xiàn)并行:

它通過事件輪詢(event loop)來實現(xiàn)并行操作,因此我們要避免阻塞操作骗奖,

Node.js可以多進(jìn)程/多線程么确徙?

image_8.png

前端的異步場景

  1. 定時器
  2. 網(wǎng)絡(luò)請求
  3. 事件綁定
  4. ES6 Promise

定時器

再回到我們的代碼

 console.log('sync...',1);
  setTimeout(()=>{
    console.log('sync...',2)
  },2000);
  console.log('sync...',3)

流程分析:

  1. 主程序調(diào)用棧
  2. 調(diào)用webAPI-setTimeout
  3. 定時器線程計數(shù)2s
  4. 事件觸發(fā)線程將定時器時間放入任務(wù)隊列
  5. 主線程通過Event Loop遍歷任務(wù)隊列執(zhí)行異步任務(wù) console.log()
console.time('test')
const test=()=>{
  let t=+new Date();
  while (true){
    if(+new Date()-t>=5000){
      break;
    }
  }
  setTimeout(()=>{
    console.log('setTimeout...')
  },2000)
}
test();
console.timeEnd('test');

注意:

  1. 定時任務(wù)可能不會按時執(zhí)行,延遲原因(等待同步任務(wù)鄙皇、等待CPU加載)
  2. 定時器嵌套5次之后最小間隔不能低于4ms

應(yīng)用場景:

  1. 防抖
  2. 節(jié)流
  3. 倒計時
  4. 動畫(存在丟幀)

案例分析

for(var i=1;i<=10;i++){
  setTimeout(function() {
    console.log(i)
  },1000*i)
}

在這個案例中,我們期望每隔1s,依次打印i的值仰挣。但實際結(jié)果卻是每隔1s重復(fù)打印11伴逸。

問題的原因在于:

  1. 定時器需要等待同步任務(wù)執(zhí)行完成,那么i的值為11膘壶。
  2. var是全局作用域

修復(fù)方案:

//使用閉包错蝴,保留當(dāng)前的作用域
for(var i=1;i<=10;i++){
  (i=>{
    setTimeout(function() {
      console.log(i)
    },1000*i)
  })(i)
}
//使用let 保留當(dāng)前的作用域
for(let i=1;i<=10;i++){
  setTimeout(function() {
    console.log(i)
  },1000*i)
}

待學(xué)習(xí)

當(dāng)我們談?wù)?cluster 時我們在談?wù)撌裁?上)

Referecnes

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市亡问,隨后出現(xiàn)的幾起案子官紫,更是在濱河造成了極大的恐慌,老刑警劉巖州藕,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件束世,死亡現(xiàn)場離奇詭異,居然都是意外死亡床玻,警方通過查閱死者的電腦和手機(jī)毁涉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锈死,“玉大人贫堰,你說我怎么就攤上這事∠诰” “怎么了严嗜?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長洲敢。 經(jīng)常有香客問我漫玄,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任睦优,我火速辦了婚禮渗常,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘汗盘。我一直安慰自己皱碘,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布隐孽。 她就那樣靜靜地躺著癌椿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪菱阵。 梳的紋絲不亂的頭發(fā)上踢俄,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機(jī)與錄音晴及,去河邊找鬼都办。 笑死,一個胖子當(dāng)著我的面吹牛虑稼,可吹牛的內(nèi)容都是我干的琳钉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼蛛倦,長吁一口氣:“原來是場噩夢啊……” “哼歌懒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起溯壶,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤歼培,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后茸塞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡查剖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年钾虐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笋庄。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡效扫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出直砂,到底是詐尸還是另有隱情菌仁,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布静暂,位于F島的核電站济丘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜摹迷,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一疟赊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧峡碉,春花似錦近哟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至地来,卻和暖如春戳玫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背靠抑。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工量九, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人颂碧。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓荠列,卻偏偏與公主長得像,于是被迫代替她去往敵國和親载城。 傳聞我的和親對象是個殘疾皇子肌似,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容