面試覆盤(一):面試官「前阿里大佬」果真厲害

前言

又到了金三銀四的找工做季啦 ✿✿ヽ(°▽°)ノ✿。我是一個入行一年多的前端菜鳥,去年夏天開始考慮換工做,陸續面試了幾家中小公司。面試過程我通常會錄音,方便結束後進行復盤。整理了幾回面試覆盤的筆記,但願對類似狀況的小夥伴有所幫助「😝 也是方便本身之後回憶」,願你們都能找到心儀的工做。❤️php

概況

  • 公司:座標上海,教育行業,前端團隊 20人+。
  • 面試官:前端負責人,前阿里P7大佬,碩士畢業轉行進入阿里。
  • 技術棧:團隊目前主要使用 vue,後期打算採用 react。
  • 面試結果:未經過 o(╥﹏╥)o 。
  • 面試感覺:面試官和藹,遇到不會的問題會適度引導,最後還給了提升建議,感受收穫滿滿。明明被虐得很慘,但仍是很開心 😁。

面試題

說明:問題末尾的數字表明對本身當時回答的打分,✔ 表明後面有關於該問題的從新整理。css

  1. 轉行緣由
  2. vue 和 react 用起來有什麼區別?2 ✔
  3. vue雙向數據綁定的原理? 數組的更新。8 ✔
  4. 組件間通訊的方式?vuex實現原理?state改變,怎麼促使視圖改變?6 ✔
  5. 爲何選用uni-app?8
  6. (搜索查看電商小程序後)你作的哪些部分?圖片加載問題,橫向爲何沒有也用intersection observer呢? Intersection Observer是瀏覽器自帶的。7 ✔
  7. 爲何要作直播插件?8
  8. 作過哪些項目優化?5 ✔
  9. webpack配置,loader和plugin區別。如何去掉冗餘的代碼? tree-shaking實現原理。5 ✔
  10. 一個新的路由,怎麼知道下載對應的文件?(擴展: 動態插入js的方式) 2 ✔
  11. 按需加載?有哪些方式?最後選擇了什麼?5
  12. 緩存,強緩存是誰設置的?html文件會緩存嗎?4 ✔
  13. cdn內容分發系統?爲何大家項目的靜態資源文件沒有放到CDN上。5 ✔
  14. 使用騰訊雲的移動直播、即時通信sdk,有什麼困難的地方?4 ✔
  15. sentry錯誤監控,錯誤是如何收集上報到平臺的?(http, websoket, 跨域)2 ✔
  16. 某某項目(簡歷中的),具體講解一下?8
  17. 項目裏遇到難點、挑戰。 4

問題2 Vue vs React

相同點:html

  1. 使用virtural DOM + Diff算法。
  2. 組件化思想。

不一樣點:前端

  1. 模板語法的不一樣:react經過JSX渲染模板,vue經過拓展的html語法進行渲染。好比react中插值、條件、循環都經過JS語法實現,vue是經過指令v-bind、v-if、v-for實現的。
  2. 監聽數據變化原理不一樣:vue經過getter、setter劫持通知數據變化,react經過比較引用的方式進行。vue使用的響應式數據,而react是不可變數據。vue改變數據直接賦值,react須要調用setState方法(用新的state替換舊的state)。

問題3 vue響應式原理

level1: vue2.0中,響應式實現的核心就是 ES5的Object.defineProperty(obj, prop, descriptor). 經過Object.defineProperty()劫持data和props各個屬性的getter和setter,getter作依賴收集,setter派發更新。總體來講是一個 數據劫持 + 發佈-訂閱者模式。vue

level2: 具體來講, ① vue初始化階段(beforeCreate以後create以前),遍歷data/props,調用Object.defineProperty給每一個屬性加上getter、setter。② 每一個組件、每一個computed都會實例化一個watcher(固然也包括每一個自定義watcher),訂閱渲染/計算所用到的所用data/props/computed,一旦數據發生變化,setter被調用,會通知渲染watcher從新計算、更新組件。node

問題4 vue組件通訊

level1: props+events 父子組件通訊( p a r e n t / parent/ children),vuex 任何組件通訊,事件中心 e m i t / emit / on 任何組件的通訊, a t t r s / attrs/ listeners 後代通訊(provide / inject)。react

level2: vuex運行機制:vuex的state做爲一個倉庫,提供數據驅動vue component渲染。視圖經過dispach派發actions,actions中能夠作一些異步操做。actions或者視圖經過commit提交給mutations,mutation去改變state。webpack

level3: 源碼分析:vuex實際上是一個Vue.js插件,插件都須要提供一個install方法,install方法調用會將Vue做爲參數傳入。Vue.user(plugin)安裝插件,也就是執行插件的install方法。會在全局混入一個beforeCreate鉤子函數,把示例化的Store保存到全部組件的this.$store中。git

level4: mutation改變state, 會觸發視圖改變的緣由?經過vue實現的,[實例化vue,把state做爲一個data屬性。] ↔️ 核心github

let Vue
function install(_Vue) {
  Vue = _Vue
  function vuexInit() {
    const options = this.$options
    console.log('vuexInit -> this.$options', this.$options)
    if (options.store) {
			// // 根實例 this --> Vue
      this.$store =
        typeof options.store === 'function' ? options.store() : options.store
    } else if (options.parent && options.parent.$store) {
			// 組件實例 this --> VueComponent, 如 APP, Home, About...
      this.$store = options.parent.$store
    }
  }
  Vue.mixin({ beforeCreate: vuexInit })
}

class Store {
  constructor(options = {}) {
    const { state = {}, mutations = {}, getters = {} } = options
    this._mutations = mutations
    // getter實現原理
    const computed = {}
    this.getters = {}
    for (let [key, fn] of Object.entries(getters)) {
      computed[key] = () => fn(this.state)
      Object.defineProperty(this.getters, key, {
        get: () => this._vm[key]
      })
    }
    this._vm = new Vue({
      data: { $$state: state }, // 核心原理
      computed
    })
  }

  commit(type, payload) {
    if (this._mutations[type]) {
      this._mutations[type](this.state, payload)
    }
  }

  get state() {
    return this._vm._data.$$state
  }
}

export default { Store, install }
複製代碼

問題6 Intersection Observer

level1: 推斷節點是否爲用戶可見,以及多少比例可見,交叉觀察器。web API中也有。

level2: 小程序中的IntersectionObserver在Web的基礎上,作了一些封裝,經過createIntersectionObserver返回一個IntersectionObserver實例。實例方法包括relativeTo、relativeToViewPort、observer、disconnect。relativeTo和relativeToViewPort,相對指定元素或視口的指定位置。observer(selector, cb),觀察指定節點,可見性發生變化時觸發回調。

level3: Web API, new IntersectionObserver(cb, options)。options裏root、rootMargin的配置,可實現小程序中relativeTo、relativeToViewPort方法的效果。另外 thresholds 屬性也蠻有趣的,在指定的幾個相交比例時觸發回調。

問題8 項目優化

  1. 移除生產環境的控制檯打印。方案不少,esling+pre-commit、使用插件自動去除,插件包括babel-plugin-transform-remove-console、uglifyjs-webpack-plugin、terser-webpack-plugin。最後選擇了terser-webpack-plugin,腳手架vue-cli用這個插件來開啓緩存和多線程打包,無需安裝額外的插件,僅需在configureWebpack中設置terser插件的drop_console爲true便可。最好仍是養成良好的代碼習慣,在開發基本完成後去掉無用的console,vscode中的turbo console就蠻好的。
  2. 第三方庫的按需加載。echarts,官方文檔裏是使用配置文件指定使用的模塊,另外一種使用babel-plugin-equire實現按需加載。element-ui使用babel-plugin-component實現按需引入。
  3. 公有樣式,好比對element-ui部分組件(如彈框、表格、下拉選框等)樣式的統一調整。公共組件,好比date-picker、upload-file等在element-ui提供的組件基本上作進一步的封裝。自定義組件包括preview-file、搜索框等。
// babel.config.js配置以下:
plugins: ['equire']
// echarts.js
const echarts = equire(['line', 'tooltip', 'legend', 'dataZoom', 'grid']);
export default echarts;
複製代碼

先後端數據交換方面,推進項目組使用藍湖、接口文檔,與後端同窗協商,規範後臺數據返回。

雅虎軍規提到的,避免css表達式、濾鏡,較少DOM操做,優化圖片、精靈圖,避免圖片空連接等。

性能問題:頁面加載性能、動畫性能、操做性能。Performance API,記錄性能數據。

winter重學前端 優化技術方案:

  1. 緩存:客戶端控制的強緩存策略。
  2. 下降請求成本:DNS 由客戶端控制,隔一段時間主動請求獲取域名IP,不走系統DNS(徹底看不懂)。TCP/TLS鏈接複用,服務器升級到HTTP2,儘可能合併域名。
  3. 減小請求數:JS、CSS打包到HTML。JS控制圖片異步加載、懶加載。小型圖片使用data-uri。
  4. 較少傳輸體積:儘可能使用SVG\gradient代替圖片。根據機型和網絡情況控制圖片清晰度。對低清晰度圖片使用銳化來提高體驗。設計上避免大型背景圖。

問題9 loader、plugin、tree shaking

loader

對模塊的源代碼進行轉換,將不一樣的語言轉換爲JS,或將內聯圖像轉換爲data url。如:文件,url-loader、file-loader。轉換編譯,babel-loader、ts-loader。模板,html-loader。樣式,style-loader、css-loader、less-loader。清理,eslint-loader。框架,vue-loader。

plugin

解決loader沒法實現的其餘事兒。好比 HtmlWebpackPlugin、CleanWebpackPlugin、webpack-bundle-analyzer、DllPlugin、HotModuleReplacementPlugin。

tree shaking

消除無用的js代碼(剔除模塊中沒有導出或引用的部分)。僅支持ES Module靜態引入方式,不支持require運行時動態引入方式。

ES6模塊引入是靜態分析的,故而可在編譯時正確判斷加載哪些代碼。

可剔除的內容有限。webpack配合uglifyJS打包文件,只能shaking部分代碼,像模塊代碼存在反作用,當即執行函數等都不能shaking。uglifyJS不進行程序流分析,只簡單判斷變量後續是否被引用、修改,不去排除有可能有反作用的代碼。(rollup會)還有,好比項目中router.js引用了頁面組件,可是在路由渲染中沒有用到,也沒法shaking掉。

webpack-deep-scope-analysis-plugin:利用webpack解析出來模塊的AST,利用scoped分析工具解析引用關係,排除掉沒有用到的模塊。

1. babel.config.js 配置,分析文件模塊依賴關係,生成AST時,保持ES6不動。
{
	"presets": [ ["env", { "modules": false }] ]
}

2.  方式1,import {Button} from 'antd'; 
    方式2,import {Buttion} from 'antd/lib/button';
           import 'antd/lib/style';
這兩種方式,tree-shaking效果差異很大。(反作用範圍不一樣)
babel-plugin-import-fix 插件,遍歷AST找出相似import {Button} from 'antd'的結構,進行轉換從新生成代碼。

3. CSS tree-shaking <https://juejin.cn/post/6844903808397475847>
  方式1:mini-css-extract-plugin + purifycss-webpack
	方式2:webpack-css-treeshaking-plugin。
	利用postCSS提供的解析器,將CSS解析成AST,遍歷獲取選擇器與js、html代碼匹配,刪除匹配不到的,返回AST,從新生成代碼。
複製代碼

問題10 懶加載路由

考點,vue-router實現原理。

level1:

  1. 將須要懶加載的子模塊,打包成單獨的文件。ES6的import()。
  2. hashChange時,根據hash變化執行特定的函數,加載子模塊。

level2: 實現的三種方式,location.hash + hashChange(),HTML5規範的pushState(IE10) + popState事件監聽,abstract nodejs默認值。

**level3:**源碼分析。路由安裝,利用mixin給每一個組件注入beforeCreated和destory鉤子函數,在Vue原型上定義 r o u t e route和 router,並進行響應式處理,定義全局的roter-link和router-view組件。根據路由配置建立映射關係。根據傳入路徑計算出新的路徑,在路勁切換過程當中,執行一系列的導航守衛函數,更改Url,渲染對應組件。

問題12 緩存

html文件也會緩存。項目中使用index.php,後端返回html內容,不會被緩存。

瀏覽器緩存策略:

  • 強制緩存:(在指定時間內,瀏覽器直接使用強緩存的內容)

    Expires:Thu.21 Jan 2019 23:59:59 GMT; (HTTP1.0)

    Cache-Control:max-age=3600(HTTP1.1,優先級更高)

    【緩存指令:no-cache須要協商緩存來驗證是否過時;no-store不緩存;public客戶端代理服務器均可以緩存;private客戶端可緩存】

  • 協商緩存:(與服務器協商,肯定資源是否更新)

    Last-Modified(服務器下發時間):Thu.21 Jan 2018 23:59:59 GMT;(HTTP1.0)

    If-Modified-Since(瀏覽器詢問) 【可能時間變了,內容沒變】

    Etag(服務器下發); (HTTP1.1)

    If-None-Match(瀏覽器詢問)

問題13 CDN

CDN,內容分發網絡,是創建再承載網基礎上的虛擬分佈式網絡,可以將源站內容緩存到全國或全球的節點服務器上。用戶就近獲取內容,提升了資源的訪問速度,分擔源站壓力。

使用DNS域名解析引導用戶來訪問cache服務器。

問題14 騰訊雲SDK難點

封裝IM類,在IM類上定義建立SDK實例,登陸/退出,羣組加入/退出,IM事件監聽和移除。

  1. 移動直播SDK。最開始沒有作小程序主播端,使用APP推流。主要作PC和H5拉流這塊內容。
  2. 直播協議有如下幾種...。
  3. 最開始使用的HLS協議,使用騰訊雲提供的TC-Player做爲播放器。遇到的問題,延遲高。
  4. 考慮更換協議,可是移動端瀏覽器不支持flv、rtmp。
  5. 騰訊雲web端拉流提供了TC-Player插件,TC-Player本質上就是利用瀏覽器自帶的video標籤來作的。
  6. 使用flv做爲直播協議,但不直接使用flv格式播放。github兩種解決方案,一種是bilibili flv.js,將flv文件流轉碼複用成MPE隨便,經過Media Source Extensions API實現視頻的播放。另外一種解決方案,是將視頻的每一幀畫面使用CANVAS繪製。

問題15 sentry

sentry錯誤日誌經過https發送到sentry的web站點。使用cors實現跨域。

  1. 應用程序(Sentry客戶端SDK) 消息上報 web端
  2. 消息處理 放入消息隊列(Redis/Rabbitmq)
  3. worker從消息隊列中取數據進行處理
  4. 最後由postgresql完成消息存儲
**request headers:**
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross site
**response headers:**
access-control-allow-origin: <http://localhost:8080>
access-control-expose-headers: x-sentry-error, retry-after, x-sentry-rate-limits
複製代碼

系列文章

面試覆盤(二):但願能夠得到簡單直接的回答

面試覆盤(三):第一次電話面試「無力」

相關文章
相關標籤/搜索