大家好,我是IT修真院北京分院第22期的學(xué)員楊剛斑芜,一枚正直碗殷、純潔精绎、善良的前端程序員
今天給大家分享一下,修真院官網(wǎng)JS(職業(yè))任務(wù)5锌妻,深度思考中的知識點——異步編程有哪幾種方法來實現(xiàn)?
1.背景介紹
Javascript語言的執(zhí)行環(huán)境是"單線程"
所謂"單線程"代乃,就是指一次只能完成一件任務(wù)。如果有多個任務(wù)从祝,就必須排隊襟己,前面一個任務(wù)完成引谜,再執(zhí)行后面一個任務(wù)牍陌,以此類推擎浴。
這種模式的好處是實現(xiàn)起來比較簡單,執(zhí)行環(huán)境相對單純毒涧;壞處是只要有一個任務(wù)耗時很長贮预,后面的任務(wù)都必須排隊等著,會拖延整個程序的執(zhí)行契讲。常見的瀏覽器無響應(yīng)(假死)仿吞,往往就是因為某一段Javascript代碼長時間運行(比如死循環(huán)),導(dǎo)致整個頁面卡在這個地方捡偏,其他任務(wù)無法執(zhí)行唤冈。
2.知識剖析
先了解下Javascript語言將任務(wù)的執(zhí)行模式。Javascript語言將任務(wù)的執(zhí)行模式分成兩種:同步(Synchronous)和異步(Asynchronous)银伟。
"同步模式":后一個任務(wù)等待前一個任務(wù)結(jié)束你虹,然后再執(zhí)行,程序的執(zhí)行順序與任務(wù)的排列順序是一致的彤避、同步的傅物;
"異步模式"則完全不同,每一個任務(wù)有一個或多個回調(diào)函數(shù)(callback)琉预,前一個任務(wù)結(jié)束后董饰,不是執(zhí)行后一個任務(wù),而是執(zhí)行回調(diào)函數(shù)圆米,后一個任務(wù)則是不等前一個任務(wù)結(jié)束就執(zhí)行卒暂,所以程序的執(zhí)行順序與任務(wù)的排列順序是不一致的、異步的娄帖。非常重要也祠。在瀏覽器端,耗時很長的操作都應(yīng)該異步執(zhí)行块茁,避免瀏覽器失去響應(yīng)齿坷,最好的例子就是Ajax操作。在服務(wù)器端数焊,"異步模式"甚至是唯一的模式永淌,因為執(zhí)行環(huán)境是單線程的,如果允許同步執(zhí)行所有http請求佩耳,服務(wù)器性能會急劇下降遂蛀,很快就會失去響應(yīng)。
3.常見問題
有哪些方法實現(xiàn)"異步模式"編程
4.解決方案
1.回調(diào)函數(shù):一般情況下干厚,應(yīng)用程序時常通過API調(diào)用庫里所預(yù)先備好的函數(shù)李滴。但是有些庫函數(shù)卻要求應(yīng)用先傳給它一個函數(shù)螃宙,好在合適的時候調(diào)用,以完成目標(biāo)任務(wù)所坯。這個被傳入的谆扎、后又被調(diào)用的函數(shù)就稱為回調(diào)函數(shù)。
function f() { ? ? ? ? ? ? ? ? ? ? ? ?function f1(callback) { ? ? ? ? ? ? ? ? ? ? ? ? ? ?setTimeout(function () { ? ? ? ? ? ? ? ? ? ? ? ? ? ?console.log('11111'); //f1的任務(wù)代碼 ? ? ? ? ? ? ? ? ? ? ? ? ? ?callback(); ? ? ? ? ? ? ? ? ? ? ? ? ? ?}, 1000); ? ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ? ? ?f1(f2); ? ? ? ? ? ? ? ? ? ? ? ?function f2() { ? ? ? ? ? ? ? ? ? ? ? ? ? ?console.log('22222') ? ? ? ? ? ? ? ? ? ? ? ? ? ?} //這(f2)是回調(diào)函數(shù) ? ? ? ? ? ? ? ? ? ? ? ?function f3(){ ? ? ? ? ? ? ? ? ? ? ? ? ? ?console.log('33333') ? ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ? ? ?f3() ? ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ?f();
采用這種方式芹助,我們把同步操作變成了異步操作堂湖,f1不會堵塞程序運行,相當(dāng)于先執(zhí)行程序的主要邏輯状土,將耗時的操作推遲執(zhí)行无蜂。 回調(diào)函數(shù)的優(yōu)點是簡單、容易理解和部署.
但是回調(diào)函數(shù)的方式存在如下的問題
1.缺點是不利于代碼的閱讀和維護(hù)蒙谓,各個部分之間高度耦合(Coupling)斥季,流程會很混亂,而且每個任務(wù)只能指定一個回調(diào)函數(shù)累驮。
2. 可能形成萬惡的嵌套金字塔酣倾,代碼不易閱讀;
3. 只能對應(yīng)一個回調(diào)函數(shù)慰照,在很多場景中成為一個限制灶挟。
2.事件監(jiān)聽:另一種思路是采用事件驅(qū)動模式。任務(wù)的執(zhí)行不取決于代碼的順序毒租,而取決于某個事件是否發(fā)生稚铣。
//jQuery中 ? ? ? ? ? ? ? ? ? ?$("#p").on("click",function(){ ? ? ? ? ? ? ? ? ? ? ? ?alert("The paragraph was clicked."); ? ? ? ? ? ? ? ? ? ?}); ? ? ? ? ? ? ? ? ? ?//JavaScript中 ? ? ? ? ? ? ? ? ? ?document.getElementById("myBtn").addEventListener("click", displayDate); ? ? ? ? ? ? ? ? ? ?function displayDate() { ? ? ? ? ? ? ? ? ? ? ? ?document.getElementById("demo").innerHTML = Date(); ? ? ? ? ? ? ? ? ? ?}
這種方法的優(yōu)點是比較容易理解,可以綁定多個事件墅垮,每個事件可以指定多個回調(diào)函數(shù)惕医,而且可以"去耦合"(Decoupling),有利于實現(xiàn)模塊化算色。缺點是整個程序都要變成事件驅(qū)動型抬伺,運行流程會變得很不清晰。
3灾梦、發(fā)布/訂閱
我們假定峡钓,存在一個"信號中心",某個任務(wù)執(zhí)行完成若河,就向信號中心"發(fā)布"(publish)一個信號能岩,其他任務(wù)可以向信號中心"訂閱"(subscribe)這個信號,從而知道什么時候自己可以開始執(zhí)行萧福。這就叫做"發(fā)布/訂閱模式"(publish-subscribe pattern)拉鹃,又稱"觀察者模式"(observer pattern)。
這個模式有多種實現(xiàn),下面采用的是Ben Alman的Tiny Pub/Sub膏燕,這是jQuery的一個插件钥屈。
首先,f2向"信號中心"jQuery訂閱"done"信號坝辫。
jQuery.subscribe("done", f2); ? ? ? ? ? ? ? ? function f1(){ ? ? ? ? ? ? ?setTimeout(function () { ? ? ? ? ?// f1的任務(wù)代碼 ? ? ? ? ?jQuery.publish("done"); ? ? ? ? ? ? ?}, 1000); ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ?jQuery.unsubscribe("done", f2);
jQuery.publish("done")的意思是篷就,f1執(zhí)行完成后,向"信號中心"jQuery發(fā)布"done"信號阀溶,從而引發(fā)f2的執(zhí)行腻脏。 此外鸦泳,f2完成執(zhí)行后银锻,也可以取消訂閱(unsubscribe)。
這種方法的性質(zhì)與"事件監(jiān)聽"類似做鹰,但是明顯優(yōu)于后者击纬。因為我們可以通過查看"消息中心",了解存在多少信號钾麸、每個信號有多少訂閱者更振,從而監(jiān)控程序的運行。
4.Promise:Promise象征著一個異步操作的最終結(jié)果饭尝。Promises交互主要通過它的then方法肯腕, then方法接受一個回調(diào)函數(shù),這個回調(diào)函數(shù)接受執(zhí)行成功的返回值或執(zhí)行失敗的錯誤原因钥平, 錯誤原因一般是Error對象实撒。
Promises對象是CommonJS工作組提出的一種規(guī)范,目的是為異步編程提供統(tǒng)一接口涉瘾。 簡單說知态,它的思想是,每一個異步任務(wù)返回一個Promise對象立叛,該對象有一個then方法负敏,允許指定回調(diào)函數(shù)。
Promise有以下幾種狀態(tài):
1.pending: 初始狀態(tài), 既不是 fulfilled 也不是 rejected秘蛇。
2.fulfilled: 表示操作被成功完成其做。
3.rejected: 表示該操作失敗。
// 條件 ? ? ? ? ? ? ? ? ? ? var isOK=true; ? ? ? ? ? ? ? ? ? ?// Promise 函數(shù) ? ? ? ? ? ? ? ? ? ? ?//它的思想是赁还,每一個異步任務(wù)返回一個Promise對象妖泄,該對象有一個then方法 ? ? ? ? ? ? ? ? ? ? ? // 允許指定回調(diào)函數(shù)。 ? ? ? ? ? ? ? ? ? ?var payPhone= new Promise( ? ? ? ? ? ? ? ? ? ? ? ?function (resolve,reject) { ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 條件為真 ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (isOK) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?var phone={ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?brand:'iphone', ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?color:'black' ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?resolve(phone); ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 條件為假 ? ? ? ? ? ? ? ? ? ? ? ? ? ?} else{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?var reason= new Error('不ok'); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?reject(reason) ? ? ? ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ? ? ?}) ? ? ? ? ? ? ? ? ? ? var buy =function () { ? ? ? ? ? ? ? ? ? ? ? ?// 連綴寫法 ? ? ? ? ? ? ? ? ? ? ? ?payPhone ? ? ? ? ? ? ? ? ? ? ? ? .then(function (res) { ? ? ? ? ? ? ? ? ? ? ? ? ? ?console.log(res) ? ? ? ? ? ? ? ? ? ? ? ? }) ? ? ? ? ? ? ? ? ? ? ? ? .catch(function (error) { ? ? ? ? ? ? ? ? ? ? ? ? ? ?console.log(error) ? ? ? ? ? ? ? ? ? ? ? ? }) ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? buy()
而且秽浇,它還有一個前面三種方法都沒有的好處:如果一個任務(wù)已經(jīng)完成浮庐,再添加回調(diào)函數(shù),該回調(diào)函數(shù)會立即執(zhí)行。所以审残,你不用擔(dān)心是否錯過了某個事件或信號梭域。這種方法的缺點就是編寫和理解,都相對比較難搅轿。
5.編碼實戰(zhàn)
6.擴展思考
promise中的互相鏈接的寫法
ES7的Async/Await
異步函數(shù)的執(zhí)行順序病涨?
計時器可以異步計算計時器的時間,時間到了之后把函數(shù)加入到j(luò)s代碼隊列的最后璧坟,如果是間隔計時器既穆,js代碼堵塞時會在隊列末尾追加多次間隔計時器指定執(zhí)行的函數(shù),并會在執(zhí)行到他們的時候一下子全部執(zhí)行出來雀鹃,因為是等完間隔要執(zhí)行函數(shù)時才追加到的末尾幻工。
7.參考文獻(xiàn)
參考一:異步操作的幾種方法
參考二:ES7中的Async/Await
參考三:jq中的異步操作
參考三:jq中的異步操作
8.更多討論
q:jQ封裝了哪些異步操作?
A黎茎;1囊颅、jQuery $.ajax()
2、$.get 傅瞻、$.post等
Q:為什么要用ajax進(jìn)行異步操作踢代。
A:為了不阻塞程序運行,服務(wù)器端都是異步嗅骄,沒有同步操作胳挎,避免卡死
Q:能更好的解釋下毀掉函數(shù)嗎?
隨便寫個函數(shù)fun1和fun2溺森,fun1運行時慕爬,他在參數(shù)里面放入一個函數(shù)fun2作為他的回調(diào)函數(shù)callback,在fun1執(zhí)行的最后儿惫,執(zhí)行callback()也就是fun2函數(shù)澡罚,這樣就完成了一個回調(diào)函數(shù)。它的目的是讓fun2放在fun1的后面執(zhí)行肾请,同時也不會因為要執(zhí)行fun2而阻塞運行留搔。
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)铛铁,非商業(yè)轉(zhuǎn)載請注明出處隔显。
視頻鏈接:
https://pan.baidu.com/s/1boT8UPT?密碼:?4r93
ppt鏈接:https://ptteng.github.io/PPT/PPT/JS-05-async.html#/
今天的分享就到這里啦,歡迎大家點贊饵逐、轉(zhuǎn)發(fā)括眠、留言、拍磚~
------------------------------------------------------------------------------------------------------------------------
技能樹.IT修真院
“我們相信人人都可以成為一個工程師倍权,現(xiàn)在開始掷豺,找個師兄捞烟,帶你入門,掌控自己學(xué)習(xí)的節(jié)奏当船,學(xué)習(xí)的路上不再迷锰饣”。
這里是技能樹.IT修真院德频,成千上萬的師兄在這里找到了自己的學(xué)習(xí)路線苍息,學(xué)習(xí)透明化,成長可見化壹置,師兄1對1免費指導(dǎo)竞思。快來與我一起學(xué)習(xí)吧?钞护!