日韩 亚洲一区二_久久vs国产综合色大全_国产精品福利在线_欧美在线一级A片免费观看欧美在线_女同性毛片60分钟

您現(xiàn)在所在的位置:首頁(yè) >學(xué)員就業(yè) > 就業(yè)寶典 > 百度、有贊、阿里前端面試總結(jié)

百度、有贊、阿里前端面試總結(jié)

來(lái)源:奇酷教育 發(fā)表於:

以下為百度、有贊、阿里的前端面試總結(jié),請大家參考:

  以下為百度、有贊、阿里的前端面試總結(jié),請大家參考:
 
  百度 WEB前端工程師 連續(xù)五面 全程3約個(gè)小時(shí)
 
  一面
 
  先完成筆試題:
 
  1、實(shí)現(xiàn)一個(gè)函數(shù),判斷輸(shū)入是不是回文字符串。
  2、兩(liǎng)種以上方式實(shí)現(xiàn)已知或者未知寬度的垂直水平居中。
  3、實(shí)現(xiàn)效果,點(diǎn)擊容器內(nèi)的圖標(biāo),圖標(biāo)邊框變成border 1px solid red,點(diǎn)擊空白處重置。
  4、請簡(jiǎn)單實(shí)現(xiàn)雙向數(shù)據(jù)綁定mvvm。
  5、實(shí)現(xiàn)Storage,使得該對(duì)象為單例,並對(duì)localStorage進(jìn)行封裝設(shè)置值setItem(key,value)和
  你的技術(shù)棧主要是react,那你說(shuō)說(shuō)你用react有什麼坑點(diǎn)?
 
  1、JSX做表達(dá)式判斷時(shí)候,需要強(qiáng)轉(zhuǎn)為boolean類(lèi)型,如:
  這是一段文本
 
  如果不使用 !!b 進(jìn)行強(qiáng)轉(zhuǎn)數(shù)據(jù)類(lèi)型,會(huì)在頁(yè)面裡面輸(shū)出 0。
 
  2、儘量不要在 componentWillReviceProps 裡使用 setState,如果一定要使用,那麼需要判斷結(jié)束條件,不然會(huì)出現(xiàn)無(wú)限重渲染,導(dǎo )致頁(yè)面崩潰。
 
  3、給組件添加ref時(shí)候,儘量不要使用匿名函數(shù),因為當(dāng)組件更新的時(shí)候,匿名函數(shù)會(huì)被當(dāng)做新的prop處理,讓ref屬性接受到新函數(shù)的時(shí)候,react內(nèi)部會(huì)先清空ref,也就是會(huì)以null為回調(diào)參數(shù)先執(zhí)行一次ref這個(gè)props,然後在以該組件的實(shí)例執(zhí)行一次ref,所以用匿名函數(shù)做ref的時(shí)候,有的時(shí)候去ref賦值後的屬性會(huì)取到null。詳情見(jiàn)
 
  4、遍歷子節(jié)點(diǎn)的時(shí)候,不要用 index 作為組件的 key 進(jìn)行傳入。
 
  我現(xiàn)在有一個(gè)button,要用react在上面綁定點(diǎn)擊事件,要怎麼做?
  我點(diǎn)擊了按鈕')    }}>      按鈕
 
  接上一個(gè)問(wèn)題,你覺得你這樣設(shè)置點(diǎn)擊事件會(huì)有什麼問(wèn)題嗎?
 
  由於onClick使用的是匿名函數(shù),所有每次重渲染的時(shí)候,會(huì)把該onClick當(dāng)做一個(gè)新的prop來(lái)處理,會(huì)將內(nèi)部緩存的onClick事件進(jìn)行重新賦值,所以相對(duì)直接使用函數(shù)來(lái)說(shuō),可能有一點(diǎn)的性能下降(個(gè)人認(rèn)為)。
 
  修改:
  我點(diǎn)擊了按鈕')  }  render() {    return
 
  當(dāng)然你在內(nèi)部聲明的不是箭頭函數(shù),然後你可能需要在設(shè)置onClick的時(shí)候使用bind綁定上下文,這樣的效果和先前的使用匿名函數(shù)差不多,因為bind會(huì)返回新的函數(shù),也會(huì)被react認(rèn)為是一個(gè)新的prop。
 
  你說(shuō)說(shuō)event loop吧
 
  首先,js是單線(xiàn )程的,主要的任務(wù)是處理用戶(hù)的交互,而用戶(hù)的交互無(wú)非就是響應(yīng)DOM的增刪改,使用事件隊(duì)列的形式,一次事件循環(huán)只處理一個(gè)事件響應(yīng),使得腳本執(zhí)行相對(duì)連續(xù),所以有了事件隊(duì)列,用來(lái)儲(chǔ)存待執(zhí)行的事件,那麼事件隊(duì)列的事件從哪裡被push進(jìn)來(lái)的呢。那就是另外一個(gè)線(xiàn )程叫事件觸發(fā)線(xiàn )程做的事情了,他的作用主要是在定時(shí)觸發(fā)器線(xiàn )程、異步HTTP請求線(xiàn )程滿(mǎn)足特定條件下的回調(diào)函數(shù)push到事件隊(duì)列中,等待js引擎空閒的時(shí)候去執(zhí)行,當(dāng)然js引擎執(zhí)行過(guò)程中有優(yōu)先級(jí)之分,首先js引擎在一次事件循環(huán)中,會(huì)先執(zhí)行js線(xiàn )程的主任務(wù),然後會(huì)去查找是否有微任務(wù)microtask(promise),如果有那就優(yōu)先執(zhí)行微任務(wù),如果沒有,在去查找宏任務(wù)macrotask(setTimeout、setInterval)進(jìn)行執(zhí)行。
 
  說(shuō)說(shuō)事件流吧
 
  事件流分為兩(liǎng)種,捕獲事件流和冒泡事件流。
 
  捕獲事件流從根節(jié)點(diǎn)開(kāi)始執(zhí)行,一直往子節(jié)點(diǎn)查找執(zhí)行,直到查找執(zhí)行到目標(biāo)節(jié)點(diǎn)。
 
  冒泡事件流從目標(biāo)節(jié)點(diǎn)開(kāi)始執(zhí)行,一直往父節(jié)點(diǎn)冒泡查找執(zhí)行,直到查到到根節(jié)點(diǎn)。
 
  事件流分為三個(gè)階段,一個(gè)是捕獲節(jié)點(diǎn),一個(gè)是處於目標(biāo)節(jié)點(diǎn)階段,一個(gè)是冒泡階段。
 
  我現(xiàn)在有一個(gè)進(jìn)度條,進(jìn)度條中間有一串文字,當(dāng)我的進(jìn)度條覆蓋了文字之後,文字要與進(jìn)度條反色,怎麼實(shí)現(xiàn)?
 
  。。。當(dāng)時(shí)我給的是js的方案,在進(jìn)度條寬度變化的時(shí)候,計(jì)算蓋過(guò)每一個(gè)文字的50%,如果超過(guò),設(shè)置文字相反顏色。
 
  當(dāng)然css也有對(duì)應(yīng)的方案,也就是 mix-blend-mode,我並沒有接觸過(guò)。
 
  對(duì)應(yīng)html也有對(duì)應(yīng)方案,也就設(shè)置兩(liǎng)個(gè)相同位置但是顏色相反的dom結(jié)構(gòu )在重疊在一起,頂層覆蓋底層,最頂層的進(jìn)度條取overflow為hidden,其寬度就為進(jìn)度。
 
  二面
 
  你為什麼要離開(kāi)上一家公司?
 
  你覺得理想的前端地位是什麼?
 
  那你意識到問(wèn)題所在,你又嘗試過(guò)解決問(wèn)題嗎?
 
  三面
 
  說(shuō)一下你上一家公司的一個(gè)整體開(kāi)發(fā)流程吧
 
  的虛擬dom是怎麼實(shí)現(xiàn)的
 
  首先說(shuō)說(shuō)為什麼要使用Virturl DOM,因為操作真實(shí)DOM的耗費(fèi)的性能代價(jià)太高,所以react內(nèi)部使用js實(shí)現(xiàn)了一套dom結(jié)構(gòu ),在每次操作在和真實(shí)dom之前,使用實(shí)現(xiàn)好的diff算法,對(duì)虛擬dom進(jìn)行比較,遞歸找出有變化的dom節(jié)點(diǎn),然後對(duì)其進(jìn)行更新操作。為了實(shí)現(xiàn)虛擬DOM,我們需要把每一種節(jié)點(diǎn)類(lèi)型抽象成對(duì)象,每一種節(jié)點(diǎn)類(lèi)型有自己的屬性,也就是prop,每次進(jìn)行diff的時(shí)候,react會(huì)先比較該節(jié)點(diǎn)類(lèi)型,假如節(jié)點(diǎn)類(lèi)型不一樣,那麼react會(huì)直接刪除該節(jié)點(diǎn),然後直接創(chuàng)建新的節(jié)點(diǎn)插入到其中,假如節(jié)點(diǎn)類(lèi)型一樣,那麼會(huì)比較prop是否有更新,假如有prop不一樣,那麼react會(huì)判定該節(jié)點(diǎn)有更新,那麼重渲染該節(jié)點(diǎn),然後在對(duì)其子節(jié)點(diǎn)進(jìn)行比較,一層一層往下,直到沒有子節(jié)點(diǎn)。
 
  的渲染過(guò)程中,兄弟節(jié)點(diǎn)之間是怎麼處理的?也就是key值不一樣的時(shí)候。
 
  通常我們輸(shū)出節(jié)點(diǎn)的時(shí)候都是map一個(gè)數(shù)組然後返回一個(gè)ReactNode,為了方便react內(nèi)部進(jìn)行優(yōu)化,我們必須給每一個(gè)reactNode添加key,這個(gè)key prop在設(shè)計(jì)值處不是給開(kāi)發(fā)者用的,而是給react用的,大概的作用就是給每一個(gè)reactNode添加一個(gè)身份標(biāo)識,方便react進(jìn)行識別,在重渲染過(guò)程中,如果key一樣,若組件屬性有所變化,則react只更新組件對(duì)應(yīng)的屬性;沒有變化則不更新,如果key不一樣,則react先銷(xiāo)毀該組件,然後重新創(chuàng)建該組件。
 
  我現(xiàn)在有一個(gè)數(shù)組[1,2,3,4],請實(shí)現(xiàn)算法,得到這個(gè)數(shù)組的全排列的數(shù)組,如[2,1,3,4],[2,1,4,3]。。。。你這個(gè)算法的時(shí)間複雜度是多少
 
  這個(gè)我沒寫(xiě)出來(lái),大概給了個(gè)思路,將每一個(gè)數(shù)組拆除倆個(gè)小數(shù)組進(jìn)行求它的全排列,然後得到的結(jié)果互相之間又進(jìn)行全排列,然後把最後的結(jié)果連接起來(lái)。。。
 
  感興趣的同學(xué)見(jiàn)數(shù)組全排列
 
  我現(xiàn)在有一個(gè)背包,容量為m,然後有n個(gè)貨物,重量分別為w1,w2,w3...wn,每個(gè)貨物的價(jià)值是v1,v2,v3...vn,w和v沒有任何關(guān)係,請求背包能裝下的最大價(jià)值。
 
  這個(gè)我也沒寫(xiě)出來(lái),也給了個(gè)思路,首先使用Q4的方法得到貨物重量數(shù)組的全組合(包括拆分成小數(shù)組的全組合),然後計(jì)算每一個(gè)組合的價(jià)值,並進(jìn)行排序,然後遍歷數(shù)組,找到價(jià)值較高切剛好能裝進(jìn)背包m的組合。
 
  本題 動(dòng)態(tài)規(guī)劃(huà)面試題,感興趣的同學(xué)請自行百度或者谷歌。
 
  四面
 
  請說(shuō)一下你的上一家公司的研發(fā)發(fā)布流程。
 
  你說(shuō)一下webpack的一些plugin,怎麼使用webpack對(duì)項(xiàng)目進(jìn)行優(yōu)化。
 
  正好最近在做webpack構(gòu )建優(yōu)化和性能優(yōu)化的事兒,當(dāng)時(shí)吹了大概15~20分鐘吧,插件請見(jiàn)webpack插件歸納總結(jié)。
 
  構(gòu )建優(yōu)化:
 
  減少編譯體積 ContextReplacementPugin、IgnorePlugin、babel-plugin-import、
 
  並行編譯 happypack、thread-loader、uglifyjsWebpackPlugin開(kāi)啟並行
 
  緩存 cache-loader、hard-source-webpack-plugin、uglifyjsWebpackPlugin開(kāi)啟緩存、babel-loader開(kāi)啟緩存
 
  預編譯 dllWebpackPlugin && DllReferencePlugin、
 
  性能優(yōu)化:
 
  減少編譯體積 Tree-shaking、
 
  緩存
 
  拆包 splitChunksPlugin、import()、
 
  的new實(shí)例和es5的new實(shí)例有什麼區(qū)別
 
  這個(gè)我覺得是一樣的(當(dāng)時(shí)因為很少看babel編譯之後的結(jié)果),面試官說(shuō)不一樣。。。後來(lái)我看了一下babel的編譯結(jié)果,發(fā)現(xiàn)只是類(lèi)的方法聲明的過(guò)程不一樣而已,最後new的結(jié)果是一樣的。。。具體答案現(xiàn)在我也不知道。。。
 
  看你簡(jiǎn)歷上寫(xiě)了canvas,你說(shuō)一下為什麼canvas的圖片為什麼過(guò)有跨域問(wèn)題
 
  圖片為什麼跨域我不知道,至今沒查出來(lái),也差不多,大概跨域原因和瀏覽器跨域的原因是一樣的吧。
 
  我現(xiàn)在有一個(gè)canvas,上面隨機(jī)布著一些黑塊,請實(shí)現(xiàn)方法,計(jì)算canvas上有多少個(gè)黑塊
 
  使用getImageData獲取像素數(shù)組,然後遍歷數(shù)組,把在遍歷節(jié)點(diǎn)的過(guò)程中,查看節(jié)點(diǎn)上下左右的像素顏色是否相同,如果相同,然後設(shè)置標(biāo)識,最後groupBy一下所有像素。(這是我當(dāng)時(shí)的方案)
 
  其他更好的答案見(jiàn)地址
 
  請手寫(xiě)實(shí)現(xiàn)一個(gè)
 
  這個(gè)就不寫(xiě)了,詳情見(jiàn)promise實(shí)現(xiàn)原理
 
  註:四面是一個(gè)超級(jí)可愛(ài)的小姐姐,電腦給我讓我寫(xiě)完之後,我說(shuō)我寫(xiě)得差不多了,然後電腦給她,然後她竟然默默的在看我的代碼,嘗試尋找我的思路,也沒有問(wèn)我實(shí)現(xiàn)思路是啥,然後我就問(wèn)她,你不應(yīng)該是讓我給你解釋我的代碼思路嗎。。。你竟然在嘗試尋找我的思路,我自己都不知道我自己是思路是啥。。。然後我兩(liǎng)都笑了,哈哈哈。最後結(jié)束的時(shí)候我說(shuō)我午飯還沒吃,她還叫了另外一個(gè)小哥哥先帶了下去吃飯,真是一個(gè)善良的小姐姐,非常感謝。
 
  五面
 
  你說(shuō)一下你的技術(shù)有什麼特點(diǎn)
 
  說(shuō)一下你覺得你最得意的一個(gè)項(xiàng)目?你這個(gè)項(xiàng)目有什麼缺陷,弊端嗎?
 
  現(xiàn)在有那麼一個(gè)團(tuán)隊(duì),假如讓你來(lái)做技術(shù)架構(gòu ),你會(huì)怎麼做?
 
  考慮到團(tuán)隊(duì)每一個(gè)前端的技術(shù)棧可能不一致,這個(gè)時(shí)候我可能選擇微前端架構(gòu ),讓每個(gè)人負(fù)責(zé)的模塊可以單獨(dú)開(kāi)發(fā),單獨(dú)部署,單獨(dú)回滾,不依賴於其他項(xiàng)目模塊,在儘可能的情況下節(jié)約團(tuán)隊(duì)成員之間的學(xué)習(xí)成本,當(dāng)然這肯定也有缺點(diǎn),那就是每個(gè)模塊都需要一個(gè)前端項(xiàng)目,單獨(dú)部署,單獨(dú)回滾無(wú)疑也加大了運(yùn)維成本。
 
  說(shuō)一下你上一家公司的主要業(yè)務(wù)流程,你參與到其中了嗎?
 
  杭州有贊
 
  一面 WEB前端工程師 電話(huà)面 全程43分鐘
 
  自我介紹
 
  說(shuō)說(shuō)從輸(shū)入URL到看到頁(yè)面發(fā)生的全過(guò)程,越詳細(xì)越好
 
  首先瀏覽器主進(jìn)程接管,開(kāi)了一個(gè)下載線(xiàn )程。
 
  然後進(jìn)行HTTP請求(DNS查詢、IP尋址等等),中間會(huì)有三次捂手,等待響應(yīng),開(kāi)始下載響應(yīng)報(bào)文。
 
  將下載完的內(nèi)容轉(zhuǎn)交給Renderer進(jìn)程管理。
 
  進(jìn)程開(kāi)始解析css rule tree和dom tree,這兩(liǎng)個(gè)過(guò)程是並行的,所以一般我會(huì)把link標(biāo)籤放在頁(yè)面頂部。
 
  解析繪製過(guò)程中,當(dāng)瀏覽器遇到link標(biāo)籤或者script、img等標(biāo)籤,瀏覽器會(huì)去下載這些內(nèi)容,遇到時(shí)候緩存的使用緩存,不適用緩存的重新下載資源。
 
  和dom tree生成完了之後,開(kāi)始合成render tree,這個(gè)時(shí)候瀏覽器會(huì)進(jìn)行layout,開(kāi)始計(jì)算每一個(gè)節(jié)點(diǎn)的位置,然後進(jìn)行繪製。
 
  繪製結(jié)束後,關(guān)閉TCP連接,過(guò)程有四次揮手。
 
  你剛剛說(shuō)了三次握手,四次揮手,那你描述一下?
 
  本人對(duì)計(jì)算機(jī)網(wǎng)絡(luò)的這些概念一直不是很熟悉,所以這個(gè)問(wèn)題回答不會(huì),這裡mark下文章,感興趣的同學(xué)查看地址
 
  剛剛Q2中說(shuō)的CSS和JS的位置會(huì)影響頁(yè)面效率,為什麼?
 
  在加載過(guò)程中不會(huì)影響到DOM樹的生成,但是會(huì)影響到Render樹的生成,進(jìn)而影響到layout,所以一般來(lái)說(shuō),style的link標(biāo)籤需要儘量放在head裡面,因為在解析DOM樹的時(shí)候是自上而下的,而css樣式又是通過(guò)異步加載的,這樣的話(huà),解析DOM樹下的body節(jié)點(diǎn)和加載css樣式能儘可能的並行,加快Render樹的生成的速度。
 
  腳本應(yīng)該放在底部,原因在於js線(xiàn )程與GUI渲染線(xiàn )程是互斥的關(guān)係,如果js放在首部,當(dāng)下載執(zhí)行js的時(shí)候,會(huì)影響渲染行程繪製頁(yè)面,js的作用主要是處理交互,而交互必須得先讓頁(yè)面呈現(xiàn)才能進(jìn)行,所以為了保證用戶(hù)體驗(yàn),儘量讓頁(yè)面先繪製出來(lái)。
 
  現(xiàn)在有一個(gè)函數(shù)A和函數(shù)B,請你實(shí)現(xiàn)B繼承
 
  方式1function B(){}function A(){}B.prototype = new A();// 方式2function A(){}function B(){  A.call(this);}// 方式
 
  剛剛你在Q5中說(shuō)的幾種繼承的方式,分別說(shuō)說(shuō)他們的優(yōu)缺點(diǎn)
 
  方式1:簡(jiǎn)單易懂,但是無(wú)法實(shí)現(xiàn)多繼承,父類(lèi)新增原型方法/原型屬性,子類(lèi)都能訪(fǎng)問(wèn)到
 
  方式2:可以實(shí)現(xiàn)多繼承,但是只能繼承父類(lèi)的實(shí)例屬性和方法,不能繼承原型屬性/方法
 
  方式3:可以繼承實(shí)例屬性/方法,也可以繼承原型屬性/方法,但是示例了兩(liǎng)個(gè)A的構(gòu )造函數(shù)
 
  說(shuō)說(shuō)CSS中幾種垂直水平居中的方式
 
  參考前面百度一面筆試題
 
  中說(shuō)的flex布局,垂直水平居中必須知道寬度嗎?
 
  是的,必須知道高度(腦子進(jìn)水了回答了必須知道,其實(shí)答案是不需要知道高度的
 
  描述一下
 
  函數(shù)執(zhí)行的上下文,可以通過(guò)apply,call,bind改變this的指向。對(duì)於匿名函數(shù)或者直接調(diào)用的函數(shù)來(lái)說(shuō),this指向全局上下文(瀏覽器為window,nodejs為global),剩下的函數(shù)調(diào)用,那就是誰調(diào)用它,this就指向誰。當(dāng)然還有es6的箭頭函數(shù),箭頭函數(shù)的指向取決於該箭頭函數(shù)聲明的位置,在哪裡聲明,this就指向哪裡。
 
  說(shuō)一下瀏覽器的緩存機(jī)制
 
  瀏覽器緩存機(jī)制有兩(liǎng)種,一種為強(qiáng)緩存,一種為協(xié)商緩存。
 
  對(duì)於強(qiáng)緩存,瀏覽器在第一次請求的時(shí)候,會(huì)直接下載資源,然後緩存在本地,第二次請求的時(shí)候,直接使用緩存。
 
  對(duì)於協(xié)商緩存,第一次請求緩存且保存緩存標(biāo)識與時(shí)間,重複請求向伺服器發(fā)送緩存標(biāo)識和最後緩存時(shí)間,服務(wù)端進(jìn)行校驗(yàn),如果失效則使用緩存。
 
  協(xié)商緩存方案:
 
  1:服務(wù)端的響應(yīng)頭,第一次請求的時(shí)候,告訴客戶(hù)端,該資源什麼時(shí)候會(huì)過(guò)期。Exprires的缺陷是必須保證服務(wù)端時(shí)間和客戶(hù)端時(shí)間嚴(yán)格同步。
 
  2:max-age,表示該資源多少時(shí)間後過(guò)期,解決了客戶(hù)端和服務(wù)端時(shí)間必須同步的問(wèn)題,
 
  3:緩存標(biāo)識,對(duì)比緩存時(shí)使用它來(lái)標(biāo)識一個(gè)緩存,第一次請求的時(shí)候,服務(wù)端會(huì)返回該標(biāo)識給客戶(hù)端,客戶(hù)端在第二次請求的時(shí)候會(huì)帶上該標(biāo)識與服務(wù)端進(jìn)行對(duì)比並返回If-None-Match標(biāo)識是否表示匹配。
 
  4:第一次請求的時(shí)候服務(wù)端返回Last-modified表明請求的資源上次的修改時(shí)間,第二次請求的時(shí)候客戶(hù)端帶上請求頭If-Modified-Since,表示資源上次的修改時(shí)間,服務(wù)端拿到這兩(liǎng)個(gè)欄位進(jìn)行對(duì)比。
 
  是這個(gè)字符串是怎麼生成的?
 
  沒答出來(lái),我當(dāng)時(shí)猜是根據(jù)文件內(nèi)容或者最後修改時(shí)間進(jìn)行的加密算法。其實(shí)官方沒有明確指定生成ETag值的方法。 通常,使用內(nèi)容的散列,最後修改時(shí)間戳的哈希值,或簡(jiǎn)單地使用版本號(hào)。
 
  現(xiàn)在要你完成一個(gè)Dialog組件,說(shuō)說(shuō)你設(shè)計(jì)的思路?它應(yīng)該有什麼功能?
 
  該組件需要提供hook指定渲染位置,默認(rèn)渲染在body下面。
 
  然後改組件可以指定外層樣式,如寬度等
 
  組件外層還需要一層mask來(lái)遮住底層內(nèi)容,點(diǎn)擊mask可以執(zhí)行傳進(jìn)來(lái)的onCancel函數(shù)關(guān)閉Dialog。
 
  另外組件是可控的,需要外層傳入visible表示是否可見(jiàn)。
 
  然後Dialog可能需要自定義頭head和底部footer,默認(rèn)有頭部和底部,底部有一個(gè)確認(rèn)按鈕和取消按鈕,確認(rèn)按鈕會(huì)執(zhí)行外部傳進(jìn)來(lái)的onOk事件,然後取消按鈕會(huì)執(zhí)行外部傳進(jìn)來(lái)的onCancel事件。
 
  當(dāng)組件的visible為true時(shí)候,設(shè)置body的overflow為hidden,隱藏body的滾動(dòng)條,反之顯示滾動(dòng)條。
 
  組件高度可能大於頁(yè)面高度,組件內(nèi)部需要滾動(dòng)條。
 
  只有組件的visible有變化且為ture時(shí)候,才重渲染組件內(nèi)的所有內(nèi)容。
 
  你覺得你做過(guò)的你覺得最值得炫耀的項(xiàng)目?
 
  螞蟻金服-體驗(yàn)技術(shù)部 資深數(shù)據(jù)可視化研發(fā)工程師
 
  一面 電話(huà)面 全程1小時(shí)24分鐘
 
  描述一下你最近做的可視化的項(xiàng)目
 
  剛剛說(shuō)的java調(diào)用js離線(xiàn )生成數(shù)據(jù)報(bào)告?java調(diào)用js的promise異步返回結(jié)果怎麼實(shí)現(xiàn)的?
 
  使用java的js引擎Nashorn,Nashorn不支持事件隊(duì)列,是要引進(jìn)polyfill,然後java調(diào)用js方法獲得java的promise對(duì)象,然後在調(diào)用該對(duì)象的then方法,回調(diào)函數(shù)為java中的某各類(lèi)的某個(gè)方法,然後while一個(gè)表示是否已執(zhí)行回調(diào)的變量,如果未執(zhí)行,則讓java主線(xiàn )程sleep,如果已經(jīng)執(zhí)行,則跳出循環(huán),表示是否已執(zhí)行回調(diào)的變量在傳入promise的回調(diào)函數(shù)中設(shè)置更改。詳情代碼見(jiàn)地址
 
  說(shuō)說(shuō)svg和canvas各自的優(yōu)缺點(diǎn)?
 
  共同點(diǎn):都是有效的圖形工具,對(duì)於數(shù)據(jù)較小的情況下,都很又高的性能,它們都使用 JavaScript 和 HTML;它們都遵守全球資訊網(wǎng)聯(lián)合會(huì) (W3C) 標(biāo)準(zhǔn)。
 
  優(yōu)點(diǎn):
 
  矢量圖,不依賴於像素,無(wú)限放大後不會(huì)失真。
 
  以dom的形式表示,事件綁定由瀏覽器直接分發(fā)到節(jié)點(diǎn)上。
 
  缺點(diǎn):
 
  形式,涉及到動(dòng)畫時(shí)候需要更新dom,性能較低。
 
  優(yōu)點(diǎn):
 
  定製型更強(qiáng),可以繪製繪製自己想要的東西。
 
  非dom結(jié)構(gòu )形式,用JavaScript進(jìn)行繪製,涉及到動(dòng)畫性能較高。
 
  缺點(diǎn):
 
  事件分發(fā)由canvas處理,繪製的內(nèi)容的事件需要自己做處理。
 
  依賴於像素,無(wú)法高效保真,畫布較大時(shí)候性能較低。
 
  你剛剛說(shuō)的canvas渲染較大畫布的時(shí)候性能會(huì)較低?為什麼?
 
  因為canvas依賴於像素,在繪製過(guò)程中是一個(gè)一個(gè)像素去繪製的,當(dāng)畫布足夠大,像素點(diǎn)也就會(huì)足夠多,那麼想能就會(huì)足夠低。
 
  假設(shè)我現(xiàn)在有5000個(gè)圓,完全繪製出來(lái),點(diǎn)擊某一個(gè)圓,該圓高亮,另外4999個(gè)圓設(shè)為半透明,分別說(shuō)說(shuō)用svg和canvas怎麼實(shí)現(xiàn)?
 
  首先,從數(shù)據(jù)出發(fā),我們的每個(gè)圓是一個(gè)數(shù)據(jù),這個(gè)數(shù)據(jù)有圓的x、y、radius、isHighlight如果是svg,直接渲染節(jié)點(diǎn)即可,然後往節(jié)點(diǎn)上邊綁定點(diǎn)擊事件,點(diǎn)擊改變所有數(shù)據(jù)的高亮屬性(必須同步執(zhí)行完成),然後讓瀏覽器進(jìn)行繪製。如果是canvas,我們需要自己綁定事件到canvans標(biāo)籤上,然後點(diǎn)擊的時(shí)候判斷點(diǎn)擊的位置是否在圓內(nèi),如果在某個(gè)圓內(nèi),則更新所有數(shù)據(jù)的高亮屬性,之後在進(jìn)行一次性繪製。
 
  剛剛說(shuō)的canvas的點(diǎn)擊事件,怎麼樣實(shí)現(xiàn)?假如不是圓,這些圖形是正方形、長(zhǎng)方形、規(guī)則圖形、不規(guī)則圖形呢
 
  針對(duì)於每一個(gè)形狀,將其抽象成shape類(lèi),每一個(gè)類(lèi)有自己的方法isPointInSide來(lái)判斷節(jié)點(diǎn)是否在圖形內(nèi),對(duì)於不規(guī)則圖形,當(dāng)做矩形處理,點(diǎn)擊的時(shí)候執(zhí)行該方法判斷點(diǎn)擊位置是否在圖形內(nèi)。
 
  那假如我的圖形可能有變形、放大、偏移、旋轉(zhuǎn)的需求呢?你的這個(gè)isPointInSide怎麼處理?
 
  這個(gè)我答不出來(lái),據(jù)面試官提示,好像有相應(yīng)的API處理變形、旋轉(zhuǎn)、放大等等之後的位置映射關(guān)係。
 
  那個(gè)這個(gè)canvas的點(diǎn)擊事件,點(diǎn)擊的時(shí)候怎麼樣快速的從這5000個(gè)圓中找到你點(diǎn)擊的那個(gè)圓(不完全遍歷5000個(gè)節(jié)點(diǎn))?
 
  可以通過(guò)預查找的形式,當(dāng)滑鼠划過(guò)的時(shí)候預先查找到滑鼠附近的一些節(jié)點(diǎn),當(dāng)點(diǎn)擊的時(shí)候在從這些預先篩選好的節(jié)點(diǎn)裡查找點(diǎn)擊下來(lái)的節(jié)點(diǎn),當(dāng)然這個(gè)方法的前提是不能影響js主線(xiàn )程的執(zhí)行,必須是異步的形式。
 
  那你用過(guò)@antv/g6,裡面有一個(gè)tree,說(shuō)說(shuō)你大學(xué)時(shí)候接觸到的tree的數(shù)據(jù)結(jié)構(gòu )是怎麼實(shí)現(xiàn)的?
 
  畢業(yè)一年多,tree的結(jié)構(gòu )大概忘記了,我當(dāng)時(shí)是這麼回答的:
 
  大學(xué)使用的是C++學(xué)的數(shù)據(jù)結(jié)構(gòu ),是用指針的形式,首先有一個(gè)根節(jié)點(diǎn),根節(jié)點(diǎn)裡有一個(gè)指針數(shù)組指向它的所有子節(jié)點(diǎn),然後每一個(gè)子節(jié)點(diǎn)也是,擁有著子節(jié)點(diǎn)的指針數(shù)組,一層一層往下,直到為葉子節(jié)點(diǎn),指針數(shù)組指向為空。
 
  還記得二叉樹嗎?描述二叉樹的幾種遍歷方式?
 
  先序遍歷:若二叉樹非空,訪(fǎng)問(wèn)根結(jié)點(diǎn),遍歷左子樹,遍歷右子樹。
 
  中序遍歷:若二叉樹非空,遍歷左子樹;訪(fǎng)問(wèn)根結(jié)點(diǎn);遍歷右子樹。
 
  後序遍歷:若二叉樹非空,遍歷左子樹;遍歷右子樹;訪(fǎng)問(wèn)根結(jié)點(diǎn)。
 
  所有遍歷是以遞歸的形似,直到沒有子節(jié)點(diǎn)。
 
  說(shuō)說(shuō)你記得的所有的排序,他們的原理是什麼?
 
  冒泡排序:雙層遍歷,對(duì)比前後兩(liǎng)個(gè)節(jié)點(diǎn),如果滿(mǎn)足條件,位置互換(huàn),直到遍歷結(jié)束。
 
  快速排序:去數(shù)組中間的那一個(gè)數(shù),然後遍歷所有數(shù),小於該數(shù)的push到一個(gè)數(shù)組,大於該數(shù)的push到另外一個(gè)數(shù)組,然後遞歸去排序這兩(liǎng)個(gè)數(shù)組,最後將所有結(jié)果連接起來(lái)。
 
  選擇排序:聲明一個(gè)數(shù)組,每次去輸(shū)入數(shù)組裡面找數(shù)組中的最大值或者最小值,取出來(lái)後push到聲明的數(shù)組中,直到輸(shū)入數(shù)組為空。
 
  說(shuō)一下你覺得你做過(guò)的最複雜的項(xiàng)目?中間遇到的困難,以及你是怎麼解決的?
 
  面試官:我這邊問(wèn)題差不多問(wèn)完了,你還有什麼問(wèn)題?
 
  我:很驚訝今天全都是問(wèn)可視化相關(guān)的,沒怎麼問(wèn)js,css,html。
 
  面試官:那我們繼續(xù)吧
 
  我:。。。
 
  那給我介紹一下react吧(面試官是做可視化開(kāi)發(fā)的,根本不懂react)
 
  以前我們沒有jquery的時(shí)候,我們大概的流程是從後端通過(guò)ajax獲取到數(shù)據(jù)然後使用jquery生成dom結(jié)果然後更新到頁(yè)面當(dāng)中,但是隨著業(yè)務(wù)發(fā)展,我們的項(xiàng)目可能會(huì)越來(lái)越複雜,我們每次請求到數(shù)據(jù),或則數(shù)據(jù)有更改的時(shí)候,我們又需要重新組裝一次dom結(jié)構(gòu ),然後更新頁(yè)面,這樣我們手動(dòng)同步dom和數(shù)據(jù)的成本就越來(lái)越高,而且頻繁的操作dom,也使我我們頁(yè)面的性能慢慢的降低。
 
  這個(gè)時(shí)候mvvm出現(xiàn)了,mvvm的雙向數(shù)據(jù)綁定可以讓我們在數(shù)據(jù)修改的同時(shí)同步dom的更新,dom的更新也可以直接同步我們數(shù)據(jù)的更改,這個(gè)特定可以大大降低我們手動(dòng)去維護(hù)dom更新的成本,mvvm為react的特性之一,雖然react屬於單項(xiàng)數(shù)據(jù)流,需要我們手動(dòng)實(shí)現(xiàn)雙向數(shù)據(jù)綁定。
 
  有了mvvm還不夠,因為如果每次有數(shù)據(jù)做了更改,然後我們都全量更新dom結(jié)構(gòu )的話(huà),也沒辦法解決我們頻繁操作dom結(jié)構(gòu )(降低了頁(yè)面性能)的問(wèn)題,為了解決這個(gè)問(wèn)題,react內(nèi)部實(shí)現(xiàn)了一套虛擬dom結(jié)構(gòu ),也就是用js實(shí)現(xiàn)的一套dom結(jié)構(gòu ),他的作用是講真實(shí)dom在js中做一套緩存,每次有數(shù)據(jù)更改的時(shí)候,react內(nèi)部先使用算法,也就是鼎鼎有名的diff算法對(duì)dom結(jié)構(gòu )進(jìn)行對(duì)比,找到那些我們需要新增、更新、刪除的dom節(jié)點(diǎn),然後一次性對(duì)真實(shí)DOM進(jìn)行更新,這樣就大大降低了操作dom的次數(shù)。
 
  那麼diff算法是怎麼運(yùn)作的呢,首先,diff針對(duì)類(lèi)型不同的節(jié)點(diǎn),會(huì)直接判定原來(lái)節(jié)點(diǎn)需要卸載並且用新的節(jié)點(diǎn)來(lái)裝載卸載的節(jié)點(diǎn)的位置;針對(duì)於節(jié)點(diǎn)類(lèi)型相同的節(jié)點(diǎn),會(huì)對(duì)比這個(gè)節(jié)點(diǎn)的所有屬性,如果節(jié)點(diǎn)的所有屬性相同,那麼判定這個(gè)節(jié)點(diǎn)不需要更新,如果節(jié)點(diǎn)屬性不相同,那麼會(huì)判定這個(gè)節(jié)點(diǎn)需要更新,react會(huì)更新並重渲染這個(gè)節(jié)點(diǎn)。
 
  設(shè)計(jì)之初是主要負(fù)責(zé)UI層的渲染,雖然每個(gè)組件有自己的state,state表示組件的狀態(tài),當(dāng)狀態(tài)需要變化的時(shí)候,需要使用setState更新我們的組件,但是,我們想通過(guò)一個(gè)組件重渲染它的兄弟組件,我們就需要將組件的狀態(tài)提升到父組件當(dāng)中,讓父組件的狀態(tài)來(lái)控制這兩(liǎng)個(gè)組件的重渲染,當(dāng)我們組件的層次越來(lái)越深的時(shí)候,狀態(tài)需要一直往下傳,無(wú)疑加大了我們代碼的複雜度,我們需要一個(gè)狀態(tài)管理中心,來(lái)幫我們管理我們狀態(tài)state。
 
  這個(gè)時(shí)候,redux出現(xiàn)了,我們可以將所有的state交給redux去管理,當(dāng)我們的某一個(gè)state有變化的時(shí)候,依賴到這個(gè)state的組件就會(huì)進(jìn)行一次重渲染,這樣就解決了我們的我們需要一直把state往下傳的問(wèn)題。redux有action、reducer的概念,action為唯一修改state的來(lái)源,reducer為唯一確定state如何變化的入口,這使得redux的數(shù)據(jù)流非常規(guī)範,同時(shí)也暴露出了redux代碼的複雜,本來(lái)那麼簡(jiǎn)單的功能,卻需要完成那麼多的代碼。
 
  後來(lái),社區(qū)就出現(xiàn)了另外一套解決方案,也就是mobx,它推崇代碼簡(jiǎn)約易懂,只需要定義一個(gè)可觀(guān)測(cè)的對(duì)象,然後哪個(gè)組價(jià)使用到這個(gè)可觀(guān)測(cè)的對(duì)象,並且這個(gè)對(duì)象的數(shù)據(jù)有更改,那麼這個(gè)組件就會(huì)重渲染,而且mobx內(nèi)部也做好了是否重渲染組件的生命周期shouldUpdateComponent,不建議開(kāi)發(fā)者進(jìn)行更改,這使得我們使用mobx開(kāi)發(fā)項(xiàng)目的時(shí)候可以簡(jiǎn)單快速的完成很多功能,連redux的作者也推薦使用mobx進(jìn)行項(xiàng)目開(kāi)發(fā)。但是,隨著項(xiàng)目的不斷變大,mobx也不斷暴露出了它的缺點(diǎn),就是數(shù)據(jù)流太隨意,出了bug之後不好追溯數(shù)據(jù)的流向,這個(gè)缺點(diǎn)正好體現(xiàn)出了redux的優(yōu)點(diǎn)所在,所以針對(duì)於小項(xiàng)目來(lái)說(shuō),社區(qū)推薦使用mobx,對(duì)大項(xiàng)目推薦使用redux。
 
  假如我一個(gè)組件有一個(gè)狀態(tài)count為1,然後我在componentDidMount()裡面執(zhí)行執(zhí)行了兩(liǎng)次this.setState({count: this.state.count++}),然後又執(zhí)行了兩(liǎng)次setTimeout(() => { this.setState({count: this.state.count++}) }, 0),最後count為多少?為什麼?
 
  為4,因為第二次執(zhí)行setState的時(shí)候,取不到第一次this.state.count++的結(jié)果,react在一輪生命周期結(jié)束後才會(huì)更新內(nèi)部的state,如果在一輪生命周期內(nèi)多次使用了setState,react內(nèi)部會(huì)有一個(gè)欄位isBatchUpdate標(biāo)識本次更新為批量更新,然後在最後render的時(shí)候將所有setState的結(jié)果提交到state中,一次性進(jìn)行更新,並且把isBatchUpdate這個(gè)欄位設(shè)置為false。
 
  針對(duì)於兩(liǎng)次setTimeout,js引擎會(huì)把這兩(liǎng)個(gè)setState丟到事件隊(duì)列中,等待js空閒了去執(zhí)行,而我們的渲染函數(shù)render是同步執(zhí)行的(react16版本默認(rèn)沒有開(kāi)啟異步渲染),所以等我們render執(zhí)行完全,也就是我們的state被同步完後,在取事件隊(duì)列裡面的setState進(jìn)行執(zhí)行,setTimeout的第二個(gè)setState也是一樣的,所以最後結(jié)果是4。
 
  說(shuō)一下你覺得你做過(guò)的最值得你說(shuō)的吧
 
  最後
 
  這幾輪面試的面試官都非常和藹好交流,百度的五輪面試不知道過(guò)了沒有,只記得五面的面試官說(shuō),你稍等一下,我去問(wèn)一下其他人對(duì)你還有什麼其他要求,然後過(guò)了一會(huì)兒HR就喊我先回去了,叫我等HR面的消息,如果沒通過(guò),也不會(huì)在聯(lián)繫我了,已經(jīng)過(guò)了四天了,但願後面有消息吧。然後有贊、螞蟻金服的兩(liǎng)個(gè)一面都過(guò)了,因為每次面完試面試官問(wèn)我還有什麼問(wèn)題嗎?我都會(huì)詢問(wèn)一下本次面試面試官對(duì)我的評(píng)論是啥。