摘要:回調(diào)地獄的問題在于寫法過于繁瑣不夠優(yōu)雅代碼維護炒雞蛋疼,所以一直被前端程序猿所詬病,尤其是維護類似代碼的時候簡直日了一群哈士奇。,對象狀態(tài)以和為分水嶺。方法返回一個帶有拒絕原因參數(shù)的對象摘自對的解釋。并且返回的也是一個對象。
這是一段旁白
“異步虐我千百遍,我待異步如初戀”?。?br>做前端的同學(xué)做異步肯定都不陌生。因為JavaScript是單線程語言(也就是說不支持多線程編程,這不是廢話么啊喂!),所以在JavaScript中處理異步問題也是經(jīng)過了幾代人的踩坑和開荒才有了今天的“花里胡哨”的解決方案。
回調(diào)(CallBack)利用回調(diào)來實現(xiàn)異步是一直以來非常有效的解決方案,而且經(jīng)久不衰。其背后的原理很簡單,就是利用JavaScript中可以將函數(shù)作為參數(shù)傳入另一個函數(shù)(萬物皆對象)。舉個栗子:
function callBack() { console.log("回調(diào)啦回調(diào)啦?。?!"); } function main(cb) { console.log("我會運行很久!") cb(); } main(callBack);
下面一段代碼中實現(xiàn)兩個函數(shù) callBack 和 main。隨后將 callBack 傳入到 main 函數(shù)中,當 main 函數(shù)執(zhí)行到一個階段時候會調(diào)用傳入的回調(diào)函數(shù) ( 此處是當main函數(shù)運行到底部時候就調(diào)用了回調(diào)函數(shù) )。運行結(jié)果不言而喻:
這樣的寫法看起來貌似還行,寫法簡單明了,一看就懂。但是這里筆者要吐槽下去年自己的智商,且聽慢慢道來:
去年在重構(gòu)項目的時候,有一個頁面需要展示 4 個下拉框而且下拉框的數(shù)據(jù)需要從后臺拉取。所以筆者在ComponentWillMount(React項目)方法中執(zhí)行了拉取數(shù)據(jù)的動作而且是分開獨立拉取,類似于:
...... ComponentWillMount() { let data = {}; fetchSelect1(); fetchSelect2(); fetchSelect3(); fetchSelect4(); } ......
最后在四個方法中將數(shù)據(jù)存儲到 data 對象中以供渲染選擇框,但是后面出現(xiàn)了一個意想不到問題:總會有一個下拉框數(shù)據(jù)拉取失敗。所以不得已采用了回調(diào)方式來處理,這里再狠狠得吐槽一下自己,如果那時候會用Promise,也不會那么尷尬。下面貼一下當時的代碼:
/* fetch data source prop selects */ router.get("/fetch-selects", function(req, resp, next) { let path1 = config.BACKEND_API.BASE_URL + "/datasource/frequency"; var reponseData = {}; httpAgent.httpRequest({}, "JSON", config.BACKEND_API.TYPE, config.BACKEND_API.HOST, config.BACKEND_API.PORT, path1, "GET", function(data) { reponseData.frequency = data; let path2 = config.BACKEND_API.BASE_URL + "/datasource/category"; httpAgent.httpRequest({}, "JSON", config.BACKEND_API.TYPE, config.BACKEND_API.HOST, config.BACKEND_API.PORT, path2, "GET", function(data) { reponseData.category = data; let path3 = config.BACKEND_API.BASE_URL + "/datasource/type"; httpAgent.httpRequest({}, "JSON", config.BACKEND_API.TYPE, config.BACKEND_API.HOST, config.BACKEND_API.PORT, path3, "GET", function(data) { reponseData.type = data; let path4 = config.BACKEND_API.BASE_URL + "/datasource/process/type"; httpAgent.httpRequest({}, "JSON", config.BACKEND_API.TYPE, config.BACKEND_API.HOST, config.BACKEND_API.PORT, path4, "GET", function(data) { reponseData.process = data; resp.json(reponseData); }, function(code, body) { }) }, function(code, body) { }) }, function(code, body) { }) }, function(code, body) { }) });
當時用的Node項目做的中間層,這是一個路由??梢钥闯鰜砥鋵嵕褪窃诶⊥甑谝粭l數(shù)據(jù)后再調(diào)用另一個函數(shù)來拉取第二條數(shù)據(jù),如此嵌套下去。好在只需要拉取 4 條數(shù)據(jù),那如果有10條乃至100條數(shù)據(jù)需要拉取怎么辦?那豈不是需要嵌套出一個很深很深的代碼結(jié)構(gòu)么?這就是臭名昭著的“回調(diào)地獄”。“回調(diào)地獄”的問題在于寫法過于繁瑣不夠優(yōu)雅、代碼維護炒雞蛋疼,所以一直被前端程序猿所詬病,尤其是維護類似代碼的時候簡直日了一群哈士奇。不僅僅是想死的心了,完全想刪庫走人啊喂!
Promise當前端異步工作處于水深火熱中時,一個英雄踏著七彩祥云而來,他,就是 Promise。讓我們相信:一個承諾,終究會被兌現(xiàn)。
Promise的由來Promise 先由社區(qū)提出來的概念,主要是用于解決前端的異步問題,慶幸的是它在ES6中也得到了實現(xiàn)。什么是Promise
Promise 是一個狀態(tài)機。這么說可能有點不好懂,上個代碼先:
new Promise(function(resolve, reject) { try { resolve("Success") } catch (e) { reject(e); } })
從上面可以看出幾個重要的點:
1,Promise是一個構(gòu)造函數(shù)。
2,新建Promise對象需要傳入執(zhí)行器函數(shù) (executor function)。
3,執(zhí)行器函數(shù)中有兩個參數(shù) resolve 和 reject。這兩個也是執(zhí)行器函數(shù)。
對此來解釋下什么叫狀態(tài)機
Promise對象有三個狀態(tài):pending, fulfilled, rejected,沒圖說個JB?
從圖中可以看出,Promise對象的初始狀態(tài)是pending ,如果經(jīng)過了 resolve 方法,狀態(tài)置為 fulfilled ;如果經(jīng)過了 reject 方法,狀態(tài)置為 rejected 。而且有三點需要明確:
1,Promise對象的狀態(tài)轉(zhuǎn)換只有 pending--->fulfilled 或者 pending--->rejected。沒有其它形式的轉(zhuǎn)換。
2,Promise 對象的狀態(tài)一經(jīng)轉(zhuǎn)換則永久凍結(jié),意思就是說比如狀態(tài)被置為 fulfilled 后,無法再回到 pending。
3,Promise對象狀態(tài)以resolve 和 reject為分水嶺。調(diào)用這個兩個方法之前,都處于pending狀態(tài)。
Promise.resolve(value)方法返回一個以給定值 value 解析后的 Promise 對象
摘自MDN對 Promise.resolve() 的解釋。簡單的理解就是它用來返回任務(wù)執(zhí)行成功后的返回值。Promise對象調(diào)用完這個方法后狀態(tài)就被置為 fulfilled。
Promise.reject()Promise.reject(reason)方法返回一個帶有拒絕原因reason參數(shù)的 Promise 對象
摘自MDN對 Promise.reject() 的解釋。Promise對象調(diào)用完這個方法后狀態(tài)就被置為 rejected。
Promise.prototype.then()看到這里可能會有這么一個問題:既然Promise用 resolve 和reject 返回處理結(jié)果,那如何獲取到這個結(jié)果呢?那么then()就大有可為了。從小標題可以看出 then 方法被放在Promise的原型上,也就是說任何一個Promise對象都可以調(diào)用這個方法,不管何時何地。then()方法的參數(shù)為兩個個執(zhí)行器函數(shù),第一個函數(shù)用來處理 resolve() 返回值,第二個函數(shù)用來處理 reject() 返回值。并且then()返回的也是一個 Promise 對象。舉個
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/96783.html
摘要:用原生寫一個多動癥的簡歷預(yù)覽地址源碼地址最近在知乎上看到方應(yīng)杭用寫了一個會動的簡歷,覺得挺好玩的,研究一下其實現(xiàn)思路,決定試試用原生來實現(xiàn)。 用原生js寫一個多動癥的簡歷 預(yù)覽地址源碼地址 最近在知乎上看到@方應(yīng)杭用vue寫了一個會動的簡歷,覺得挺好玩的,研究一下其實現(xiàn)思路,決定試試用原生js來實現(xiàn)。 showImg(https://segmentfault.com/img/remot...
JavaScript異步與回調(diào) 一、前言 首先我們要記住的是異步和并行有著本質(zhì)的區(qū)別?! 〔⑿校唵蝸碚f是一般指并行計算,就是說同一時刻有多條指令同時被執(zhí)行,這些指令可能執(zhí)行于同一CPU的多核上,或者多個CPU上,或者多個物理主機甚至多個網(wǎng)絡(luò)中?! ⊥?,一般指按照預(yù)定的順序依次執(zhí)行任務(wù),只有當上一個任務(wù)完成后,才開始執(zhí)行下一個任務(wù)?! ‘惒剑c同步相對應(yīng),異步指的是讓CPU暫時擱置當前任...
摘要:使用官方的的另外一種版本和一起使用自動配置了一個項目支持。需要的依賴都在文件中。帶靜態(tài)類型檢驗,現(xiàn)在的第三方包基本上源碼都是,方便查看調(diào)試。大型項目首選和結(jié)合,代碼調(diào)試維護起來極其方便。 showImg(https://segmentfault.com/img/bVbrTKz?w=1400&h=930); 阿特伍德定律,指的是any application that can be wr...
閱讀 1721·2023-04-26 02:30
閱讀 1049·2021-11-10 11:36
閱讀 1396·2021-10-08 10:14
閱讀 3522·2021-09-28 09:35
閱讀 1562·2021-08-23 09:47
閱讀 2561·2019-08-30 15:56
閱讀 1483·2019-08-30 15:44
閱讀 1774·2019-08-30 13:59