異步

JS中的單線程指的是在同一個時間內(nèi)只能做一件事情溜徙。

好處:避免DOM渲染的沖突冰木。瀏覽器根據(jù)HTML文件初始化需要渲染DOM,JS也可以修改DOM饮六,為了避免兩種方式對同一個DOM元素的處理發(fā)生沖突羡洁,JS執(zhí)行時玷过,渲染要暫停處理,除此之外筑煮,兩段JS代碼也不能同時執(zhí)行辛蚊。

引入的問題:造成頁面的卡頓。當(dāng)頁面渲染過程中真仲,執(zhí)行JS加載某一段數(shù)據(jù)袋马,需要等到數(shù)據(jù)加載完畢后瀏覽器才能繼續(xù)渲染操作,導(dǎo)致用戶體驗很差秸应。

如何解決單線程處理的缺陷虑凛?——異步

1碑宴、setTimeOut(callback , [time])

直接跳過該段代碼,繼續(xù)執(zhí)行下面的主線程代碼桑谍,time毫秒之后把callback函數(shù)放入到異步隊列中(或者省略掉time宏怔,直接把callback函數(shù)放入到異步隊列)拧烦。當(dāng)主線程的代碼執(zhí)行完畢后沃粗,再在異步隊列中取函數(shù)執(zhí)行墙懂。

2、$.ajax( {url:'xxxxx' 盈罐,success:callback })

當(dāng)遇到ajax代碼需要從其他頁面加載數(shù)據(jù)時,也是跳過這段代碼闪唆,繼續(xù)在主線程中執(zhí)行JS代碼盅粪,當(dāng)url地址的數(shù)據(jù)加載完畢后,把callback函數(shù)放入異步隊列悄蕾,等待主線程執(zhí)行完畢后的回調(diào)票顾。

好處:釋放了加載數(shù)據(jù)這段空期,代碼能夠繼續(xù)執(zhí)行帆调。

引入的問題:異步的操作沒有按照書寫的方式執(zhí)行奠骄,可讀性差。而且番刊,callback中不容易模塊化含鳞,當(dāng)新增需求,只能在callback函數(shù)中補充功能的實現(xiàn)芹务,這就違反了開放封閉原則蝉绷,也不利于測試和維護。

異步的本質(zhì)——實現(xiàn)方式——event-loop

同步代碼在主線程中按次立即執(zhí)行枣抱,遇到異步函數(shù)時則略過熔吗,當(dāng)某些事件被觸發(fā)(比如定時器或者數(shù)據(jù)加載完畢),則把異步函數(shù)放入到異步隊列中佳晶。最后桅狠,當(dāng)同步代碼執(zhí)行完畢,則啟用事件輪詢機制轿秧,如果在隊列中有異步函數(shù)中跌,則取出來放入到主線程中運行,如果是空隊列淤刃,則繼續(xù)輪詢監(jiān)聽異步隊列中是否有新的異步函數(shù)被插入晒他。

如何解決異步引入的問題?——deferred

這里從jQuery1.5版本前后ajax的特性說起逸贾。

jQuery1.5版本前的ajax語法:

var ajax = $.ajax({

? ? ? url:'xxxxxxx'陨仅,

? ? ? success:function(){

? ? ? ? ? xxxxxxxxxxxxxxx

? ? ? },

? ? error:function(){

? ? ? ? ? xxxxxxxxxxxxxxx

? ? ? }? ?

})

//返回的是一個XHR對象

使用這種方式津滞,當(dāng)需要回調(diào)函數(shù)success的代碼時,不得不在success代碼內(nèi)部添加灼伤,嚴(yán)重影響了代碼的安全性触徐。所以,在之后的jQuery1.5版本以后狐赡,對這種行為進行了規(guī)避:

var ajax = $.ajax('url')

ajax.done(function(){xxxxxx}).fail(function(){xxxxxx}).done(function(){......})......

//返回一個deferred對象

或者:

ajax.then(function(){xxx}撞鹉,function(){xxx}).then(function(){xxx},function(){xxx})...

//這邊引入的ajax.then格式就和之后提出的promise標(biāo)準(zhǔn)很相近了

使用ajax鏈?zhǔn)讲僮鲾U展success或者error代碼颖侄。

jQuery1.5的變化鸟雏,從本質(zhì)上來說它無法改變JS異步和單線程的本質(zhì),實際上它是一種語法糖的形式览祖,但是解耦了代碼孝鹊,從寫法上杜絕了callback這種形式,很好地體現(xiàn)了開放封閉原則展蒂。

如何使用jQuery Deferred又活?

如下是一段簡單的異步操作代碼,不利于擴展操作:

var wait = function () {

? ? ? ? ? var task = function () {

? ? ? ? ? ? ? ? ? console.log('執(zhí)行完畢')

? ? ? ? ? }

? ? ? ? ? setTimeOut(task锰悼,2000)

}

wait()

現(xiàn)在新增需求柳骄,需要在執(zhí)行完畢之后進行某些特別復(fù)雜的操作,而且可能分為好幾個步驟箕般,這里就需要引入deferred對象來進行拓展:

function waitHandle () {

? ? ? //創(chuàng)建一個deferred對象

? ? ? ? var dtd = $.Deferred()

? ? ? //要求傳入一個deferred對象

? ? ? ? var wait = function (dtd) {

? ? ? ? ? ? ? ? ? var task = function () {

? ? ? ? ? ? ? ? ? ? ? ? ? console.log('執(zhí)行完畢')

? ? ? ? ? ? ? ? ? ? ? ? //表示異步任務(wù)已經(jīng)完成

? ? ? ? ? ? ? ? ? ? ? ? ? dtd.resolve()

? ? ? ? ? ? ? ? ? ? ? ? ? //表示異步任務(wù)失敗或出錯

? ? ? ? ? ? ? ? ? ? ? ? ? dtd.reject()

? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? setTimeOut(task耐薯,2000)

? ? ? ? ? ? ? ? //要求返回deferred對象

? ? ? ? ? ? ? ? return dtd

? ? ? ? }

? ? ? ? //注意:這里一定要有返回值

? ? ? ? return wait(dtd)

}

//返回deferred對象

var w = waitHandle()

//調(diào)用deferred對象的then方法。then方法傳入兩個函數(shù)

w.then(function(){

? ? ? ? ? ? console.log(‘ok 1’)

}隘世,function(){

? ? ? ? ? ? console.log(‘error 1’)

}).then(function(){

? ? ? ? ? ? console.log(‘ok 2’)

}可柿,function(){

? ? ? ? ? ? console.log(‘error 2’)

})

promise對象最初的引入——Deferred.promise()——分離API

如上述代碼所示,dtd的API分為兩大類丙者,它們的用意不同复斥。

第一類是主動觸發(fā)的:dtd.resolve(),dtd.reject()

第二類是被動監(jiān)聽的:dtd.then()械媒,dtd.done()目锭,dtd.fail()

如果在then前面主動觸發(fā)resolve或者reject,后面負(fù)責(zé)監(jiān)聽的API會根據(jù)距離最近的監(jiān)聽結(jié)果來執(zhí)行自己相應(yīng)的代碼纷捞,發(fā)生意想不到的結(jié)果痢虹。

為了把這兩類API分開,引入deferred.promise()對象:

var wait = function (dtd) {

? ? ? ? ? ? ? ? ? var task = function () {

? ? ? ? ? ? ? ? ? ? ? ? ? console.log('執(zhí)行完畢')

? ? ? ? ? ? ? ? ? ? ? ? ? dtd.resolve()

? ? ? ? ? ? ? ? ? ? ? ? ? dtd.reject()

? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? setTimeOut(task主儡,2000)

? ? ? ? ? ? ? ? //注意這里返回的是promise奖唯,而不是deferred對象

? ? ? ? ? ? ? ? return dtd.promise(()

? ? ? ? }

? ? ? ? ? ? ? ? ..............

//經(jīng)過上面的改動,w接收的是一個promise對象

var w = waitHandle()

$.when(w)

? .then(function(){

? ? ? ? ? console.log(‘ok 1’)

? })

? .then(function(){

? ? ? ? ? console.log(‘ok 2’)

? })

//此處若執(zhí)行w.reject會報錯糜值,因為promise對象中沒有這個方法

ES6中的Promise


淺談Promise的實現(xiàn):

Promise 對象用于表示一個異步操作的最終狀態(tài)(完成或失敺峤荨)坯墨,以及其返回的值

一些舊版瀏覽器不支持Promise,可以在<script>中引入bluebird

異常捕獲規(guī)定:then()只能接收一個參數(shù)病往,最后統(tǒng)一由catch捕獲異常捣染。

catch不僅能捕獲程序邏輯之外語法的錯誤,還能捕獲業(yè)務(wù)邏輯之內(nèi)錯誤停巷,reject需要傳入?yún)?shù)耍攘,不應(yīng)該為空參數(shù)

result.then(function (img) {

? ? ? ? alert(img.width)

}).then(function(img) {

? ? ? ? alert(img.height)

}).catch(function(ex) {

? ? ? ? alert(ex)

})

多個串聯(lián)

應(yīng)用場景:按照順序執(zhí)行

var src1 = './imgDemo1.png'

var result1 = loadImg(src1)

var src2 = './imgDemo2.png'

var result2 = loadImg(src2)

result1.then(function (img) {

? ? ? ? alert(img.width)

? ? ? ? return result2

}).then(function(img) {

? ? ? ? alert(img.height)

}).catch(function(ex) {

? ? ? ? alert(ex)

})

Promise.all & Promise.race

Promise.all接收一個promise對象的數(shù)組

待全部完成之后,統(tǒng)一執(zhí)行success:

Promise.all([ result1 ], [ result2 ]).then(datas=> {

? ? //接收到的datas是一個數(shù)組畔勤,依次包含多個promise返回的內(nèi)容

? ? console.log(datas[ 0 ])

? ? console.log(datas[ 1 ])

})

Promise.all可以將多個Promise實例包裝成一個新的Promise實例蕾各。同時,成功和失敗的返回值是不同的庆揪,成功的時候返回的是一個結(jié)果數(shù)組示损,而失敗的時候則返回最先被reject失敗狀態(tài)的值。

Promise.race接收一個包含多個promise對象的數(shù)組

只要有一個完成嚷硫,就執(zhí)行success

Promise.all([ result1 ], [ result2 ]).then(data=> {

//接收到的data是最先執(zhí)行完的promise的返回值

? ? console.log(data)

})

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市始鱼,隨后出現(xiàn)的幾起案子仔掸,更是在濱河造成了極大的恐慌,老刑警劉巖医清,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件起暮,死亡現(xiàn)場離奇詭異,居然都是意外死亡会烙,警方通過查閱死者的電腦和手機负懦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柏腻,“玉大人纸厉,你說我怎么就攤上這事∥迳” “怎么了颗品?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沃缘。 經(jīng)常有香客問我躯枢,道長,這世上最難降的妖魔是什么槐臀? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任锄蹂,我火速辦了婚禮,結(jié)果婚禮上水慨,老公的妹妹穿的比我還像新娘得糜。我一直安慰自己敬扛,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布掀亩。 她就那樣靜靜地躺著舔哪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪槽棍。 梳的紋絲不亂的頭發(fā)上捉蚤,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天,我揣著相機與錄音炼七,去河邊找鬼缆巧。 笑死,一個胖子當(dāng)著我的面吹牛豌拙,可吹牛的內(nèi)容都是我干的陕悬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼按傅,長吁一口氣:“原來是場噩夢啊……” “哼捉超!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唯绍,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤拼岳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后况芒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惜纸,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年绝骚,在試婚紗的時候發(fā)現(xiàn)自己被綠了耐版。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡压汪,死狀恐怖粪牲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情止剖,我是刑警寧澤虑瀑,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站滴须,受9級特大地震影響舌狗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜扔水,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一痛侍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦主届、人聲如沸赵哲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枫夺。三九已至,卻和暖如春绘闷,著一層夾襖步出監(jiān)牢的瞬間橡庞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工印蔗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扒最,地道東北人。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓华嘹,卻偏偏與公主長得像吧趣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子耙厚,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,573評論 2 359

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

  • -al -ial/-ual/-ical/-el/-le 主要做形容詞强挫,還可以作名詞。 ?來源于中古英語中的-al和...
    單詞家族閱讀 5,360評論 0 0
  • 我最想實現(xiàn)的一個愿望薛躬, 是找到一條永生不死的路纠拔, 包括身體和心靈, 盡管這一點也不著邊際泛豪, 但是我就是在這樣不切實...
    D木頭仁閱讀 432評論 0 3
  • ? 導(dǎo)語:為什么做銷售诡曙?別以為能說就能做好銷售,更別以為能吹就能出單略水!電話銷售更是不能這樣想當(dāng)然的認(rèn)為价卤。 老魚早前...
    0c80af0c57a1閱讀 754評論 0 1
  • 一些想法:這次真的終了! 我寫的渊涝,所分享的東西都是我看到慎璧,聽到,以及胡思亂想想到的東西跨释;我只是把觸動我的內(nèi)容轉(zhuǎn)述出...
    haominzeng閱讀 466評論 0 0
  • 胸私,,鳖谈,岁疼,,缆娃,捷绒,
    衛(wèi)凱旋2410閱讀 155評論 0 0