D3.js中強(qiáng)制異步文件讀取同步的幾種方法
發(fā)現(xiàn)問(wèn)題
在使用d3.js時(shí),我們經(jīng)常會(huì)使用d3.csv()
或者d3.json()
函數(shù)來(lái)從文件中讀取出數(shù)據(jù),不幸的是,偶爾代碼的結(jié)果并不是我們預(yù)料的那樣。習(xí)慣了過(guò)程式編程的我開(kāi)始的時(shí)候也是這樣,最讓人頭疼的是javascript并不會(huì)告訴你問(wèn)題出在哪里了。我第一次遇到這個(gè)問(wèn)題的時(shí)候,找了半天bug,確定代碼主體部分沒(méi)有問(wèn)題之后,我只能開(kāi)始使用console.log()
將變量一個(gè)一個(gè)的輸出到控制臺(tái)里。
第一次遇到這個(gè)問(wèn)題時(shí)的圖片是這樣的:
問(wèn)題出在第72行和第75行,中間幾行完全沒(méi)有對(duì)ordertxt進(jìn)行操作,但是最后的結(jié)果就是和預(yù)想的輸出不吻合,后來(lái)找了個(gè)其他方法把這個(gè)問(wèn)題給解決了,今天又遇到了類(lèi)似的這個(gè)問(wèn)題,就下決心來(lái)拔掉這根刺。
試驗(yàn)
\<script\> console.log("before csv1 "); d3.csv("flowers.csv", function(data) {console.log(data)}); console.log("before csv2"); d3.csv("flowers.csv",function(error,data2) {console.log(error, data2)}); \</script\>
believe it or not,上面的代碼將產(chǎn)生下面圖中的輸出結(jié)果,因?yàn)閖avascript的 異步特性 。說(shuō)到異步,大部分時(shí)候是讓人開(kāi)心的,但偶爾也會(huì)令人頭疼,至少在這里,就是令人頭疼。
解決方法1
第一次遇到這個(gè)問(wèn)題的時(shí)候,我巧妙的繞開(kāi)了這個(gè)問(wèn)題,使用的方法是:我把數(shù)據(jù)的處理放在了d3.csv(“flowers.csv”,function(data){dealWithData()…})
回調(diào)函數(shù)里面,這樣數(shù)據(jù)的處理就和d3的讀文件操作變成了綁在一根繩上的螞蚱了,要么一起執(zhí)行完,要么都不執(zhí)行。貌似世界和平了,但是今天下午又遇到了這個(gè)問(wèn)題,而且數(shù)據(jù)的變化是隨時(shí)隨地的,可不是和上一次遇到的那樣,所有會(huì)發(fā)生的變化都可以預(yù)先寫(xiě)成代碼的。于是我開(kāi)始了對(duì)解決方法的苦苦追尋。
解決方法2
第二種方法是借助一些helper類(lèi)庫(kù)(queue.js)來(lái)強(qiáng)制數(shù)據(jù)在加載完成之后才去觸發(fā)相應(yīng)的操作。這種方法是我在網(wǎng)上看到的,并沒(méi)有去親自試過(guò),也許會(huì)成功,但是對(duì)于我們會(huì)變化的數(shù)據(jù),不能提前將處理邏輯寫(xiě)出代碼,這種方法還是不合格的。
解決方法3
第三種方法是在stack overflow里查到的,試了一下是可以的,他這里用的是d3.text()函數(shù),將文件先load進(jìn)來(lái),然后再使用d3.csv.parse
或者d3.csv.parseRows
,這樣就會(huì)是同步的了。參考文末的Reference 3的實(shí)現(xiàn)。
解決方法4
方法4是我自己想出來(lái)的,最近幾天一直在做angular和d3結(jié)合在一起的工作,我就在想能否借助angular來(lái)幫助我們完成呢?萬(wàn)幸,Angular中確實(shí)有這么一個(gè)函數(shù),似乎就是為這個(gè)問(wèn)題量身定做的,且解決了前面的方法都沒(méi)有解決的數(shù)據(jù)后期動(dòng)態(tài)變化的問(wèn)題。這個(gè)函數(shù)就是 $watch
函數(shù)。
$watch列表
每當(dāng)我們?cè)谝晥D中追蹤一個(gè)事件時(shí),會(huì)給它注冊(cè)一個(gè)回調(diào)函數(shù),然后希望在頁(yè)面中觸發(fā)該事件時(shí)調(diào)用這個(gè)回調(diào)函數(shù)。比如AngularJS中最令人印象深刻的雙向綁定,在input中輸入一個(gè)字母,有著相同ng-model的變量就會(huì)跟著input的輸入而發(fā)生改變。
發(fā)生這一變化的原因是我們把UI中的輸入字段綁定給了$scope.name
屬性,為了更新這個(gè)視圖,Angular需要 追蹤變化 ,是通過(guò)給$watch
列表添加一個(gè)監(jiān)控函數(shù)做到這一點(diǎn)的。
臟檢查
臟檢查是一個(gè)簡(jiǎn)單的過(guò)程,可歸結(jié)為一個(gè)非?;A(chǔ)的概念:檢查值是否發(fā)生了變化,而整個(gè)應(yīng)用還沒(méi)同步該變化。Angular會(huì)遍歷$watch
列表,只要有任何的值發(fā)生比變化,應(yīng)用將會(huì)退回到$watch
循環(huán)中,直到檢測(cè)到不在發(fā)生任何變化。
$watch
$scope
對(duì)象上的$watch
方法會(huì)給Angular事件循環(huán)內(nèi)的每個(gè)$digest調(diào)用裝配一個(gè)臟檢查,如果在檢測(cè)到變化,Angular總是會(huì)返回$digest
循環(huán)。
$watch
函數(shù)本身接受兩個(gè)必要參數(shù)和一個(gè)可選的參數(shù),第一個(gè)參數(shù)是watch的對(duì)象,第二個(gè)參數(shù)是 回調(diào)函數(shù) ,一旦watch的對(duì)象變了的時(shí)候觸發(fā);可選的參數(shù)是一個(gè)bool值,告訴Angular是否檢查 嚴(yán)格相等 。
關(guān)于回調(diào)函數(shù)和嚴(yán)格相等,還有一些想說(shuō)的。
回調(diào)函數(shù)
我一直是這么理解回調(diào)函數(shù)的,研究生的導(dǎo)師會(huì)分配給每個(gè)研究生活去干,而他自己也有自己的事情,如果給某個(gè)研究生安排的活他做好了,就過(guò)來(lái)給他說(shuō)一聲,導(dǎo)師負(fù)責(zé)匯總,將活寫(xiě)成論文發(fā)表出去。這其實(shí)就是回調(diào)函數(shù)工作的原理。當(dāng)然導(dǎo)師不可能在這邊等著研究生干活,自己什么都不干;或者自己什么都干了,也沒(méi)研究生什么事了。
嚴(yán)格相等
比如有一個(gè)數(shù)組,a=【1,2,3】,后面修改了a【0】=2,在AngularJS看來(lái),這個(gè)數(shù)組并沒(méi)有發(fā)生變化,因?yàn)檫€是3個(gè)變量,而如果從嚴(yán)格意義上來(lái)說(shuō),它已經(jīng)發(fā)生了變化,這就是嚴(yán)格相等和相等的不同,在javascript中,也有==和===的區(qū)別。
實(shí)現(xiàn)
寫(xiě)到這里,大家應(yīng)該知道該怎么做了,即調(diào)用$watch
函數(shù)來(lái)觀測(cè)我們需要關(guān)注的data,每當(dāng)發(fā)生變化的時(shí)候,就根據(jù)新的data,重新繪制圖標(biāo)。因此,我們最好將render的過(guò)程抽象成一個(gè)函數(shù),方便我們后期調(diào)用。比如,我們想要觀測(cè)data數(shù)組的變化,并且根據(jù)它的變化來(lái)重新繪制圖片。那么我們的代碼實(shí)現(xiàn)就應(yīng)該像下面這樣。
scope.$watch("data", function() { render(); //render函數(shù)是繪制的過(guò)程,換成自己的即可。 },true);
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。
相關(guān)文章
微信小程序獲取微信運(yùn)動(dòng)步數(shù)的實(shí)例代碼
本篇文章主要介紹了微信小程序微信運(yùn)動(dòng)步數(shù)的實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07javascript實(shí)現(xiàn)顏色漸變的方法
這篇文章介紹了javascript實(shí)現(xiàn)顏色漸變的方法,有需要的朋友可以參考一下2013-10-10JavaScript高級(jí)編程之Array的用法總結(jié)
這篇文章主要為大家介紹了JavaScript中Array常見(jiàn)用法的總結(jié),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-11-11使用ionic(選項(xiàng)卡欄tab) icon(圖標(biāo)) ionic上拉菜單(ActionSheet) 實(shí)現(xiàn)通訊錄界面切換實(shí)例
這篇文章主要介紹了使用ionic(選項(xiàng)卡欄tab) icon(圖標(biāo)) ionic上拉菜單(ActionSheet) 實(shí)現(xiàn)通訊錄界面切換實(shí)例代碼,需要的朋友可以參考下2017-10-10手寫(xiě)Spirit防抖函數(shù)underscore和節(jié)流函數(shù)lodash
這篇文章主要介紹了手寫(xiě)Spirit防抖函數(shù)underscore和節(jié)流函數(shù)lodash,接下來(lái)將會(huì)帶你們了解下這兩者的區(qū)別,以及我們?cè)撊绾问謱?xiě)實(shí)現(xiàn)這兩個(gè)函數(shù)2022-03-03javascript encodeURI和encodeURIComponent的比較
在進(jìn)行SaaS前端開(kāi)發(fā)的時(shí)候,大家經(jīng)常會(huì)用到兩個(gè)JavaScriptNative函數(shù):encodeURI 和 encodeURIComponent。這篇文章詳細(xì)解釋這兩個(gè)函數(shù)的用途并比較它們的不同之處2010-04-04