只寫後臺管理的前端要怎麼提升自己

我不吃饼干呀發表於2024-09-30

本人寫了五年的後臺管理。每次面試前就會頭疼,因為寫的頁面除了表單就是表格。抱怨過苦惱過也後悔過,但是站在現在的時間點回想以前,發現有很多事情可以做的更好,於是有了這篇文章。

本文首發在 https://juejin.cn/post/7360528073631318027

寫優雅的程式碼

一道面試題

大概兩年以前,面試美團的時候,面試官讓我寫一道程式碼題,時間單位轉換。具體的題目我忘記了。

原題目我沒做過,但是我寫的業務程式碼程式碼裡有類似的單位轉換,後端返回一個數字,單位是kb,而我要展示成 KBMB 等形式。大概寫一個工具函式(具體怎麼寫的忘記了,不過功能比這個複雜點):

function formatSizeUnits(kb) {
    let units = ['KB', 'MB', 'GB', 'TB', 'PB'];
    let unitIndex = 0;

    while (kb >= 1024 && unitIndex < units.length - 1) {
        kb /= 1024;
        unitIndex++;
    }

    return `${kb.toFixed(2)} ${units[unitIndex]}`;
}

而在此之前,是一個後端同學寫的程式碼(說起來,後臺管理系統前端人力不夠後端幫忙寫好像是常規操作,後端總覺得寫前端簡單,而我只能說你們那程式碼寫的,一言難盡……),如下:

function formatSizeUnits(kb) {
    var result = '';

    if (kb < 1024) {
        result = kb + ' KB';
    } else if (kb < 1024 * 1024) {
        result = (kb / 1024).toFixed(2) + ' MB';
    } else if (kb < 1024 * 1024 * 1024) {
        result = (kb / 1024 / 1024).toFixed(2) + ' GB';
    } else {
        result = (kb / 1024 / 1024 / 1024).toFixed(2) + ' TB';
    }

    return result;
}

雖然功能都一樣,但是我寫在面試的時候寫了上面的程式碼得到了面試官的讚揚,也因此非常順利的透過了面試。而如果我寫成了下面的樣子,估計不會有這種效果。

如何提升程式碼質量

想提升程式碼質量,最理想的是靠 code review ,但實際上這玩意在大多數公司根本就不存在。其次就只能多看看大佬們寫的程式碼,但是一來後臺管理本來就沒太大難度很少有大佬,二來很多時候一個後臺管理系統就一兩個人負責。

還好現在有了各種 AI 工具,可以非常方便的最佳化自己的程式碼了。

還是上面的問題,看看 GPT 給的答案

// 提問:寫一個工具函式,對檔案大小的單位進行轉換,加註釋
// 回答:下面是一個JavaScript工具函式,它接受檔案大小、初始單位、目標單位和小數位數,然後返回目標單位下的檔案大小。

/**
 * 將檔案大小從一個單位轉換為另一個單位。
 *
 * @param {number} size 檔案大小。
 * @param {string} fromUnit 初始單位('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB')。
 * @param {string} toUnit 目標單位('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB')。
 * @param {number} [decimalPoint=2] 結果保留的小數位數,預設為2。
 * @return {string} 轉換後的檔案大小,帶單位。
 */
function convertFileSize(size, fromUnit, toUnit, decimalPoint = 2) {
  // 定義單位與位元組之間的轉換關係
  const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
  // 獲取初始單位和目標單位的索引
  const fromIndex = units.indexOf(fromUnit);
  const toIndex = units.indexOf(toUnit);

  // 如果單位不在列表中,丟擲錯誤
  if (fromIndex === -1 || toIndex === -1) {
    throw new Error('Invalid units');
  }

  // 計算初始單位與目標單位之間的轉換系數
  const exponent = toIndex - fromIndex;
  // 計算結果大小
  const resultSize = size / Math.pow(1024, exponent);

  // 返回格式化後的結果
  return parseFloat(resultSize.toFixed(decimalPoint)) + ' ' + toUnit;
}

// 示例使用
console.log(convertFileSize(1, 'GB', 'MB')); // 輸出: 1024.00 MB
console.log(convertFileSize(1, 'MB', 'KB')); // 輸出: 1024.00 KB
console.log(convertFileSize(1, 'KB', 'B'));  // 輸出: 1024.00 B
console.log(convertFileSize(1, 'MB', 'GB', 5)); // 輸出: 0.00098 GB

還能說什麼,我只能說 NB!(經評論區提示,此段程式碼可能有問題,建議大家在使用AI工具時,重點是借鑑思路,直接使用程式碼需要謹慎~)

我現在每次寫大段邏輯之後都習慣拿給 AI 看看,有什麼更好的實現方式,或者用什麼設計模式。AI 是非常低成本且高效提升程式碼質量的工具。

學會封裝

一個功能用到了好多次,為什麼不封裝成元件?一個元件用到了好幾個專案,為什麼不單獨寫個npm包?差不多的專案建立了好幾個,為什麼不封裝成腳手架?

你說,沒時間,沒必要,複製貼上反而更快。

那你就完全沒理解,這麼做不一定是為了讓工作更快完成,而是可以讓你在年年終述職時更有話說(你就算寫了一百個表單表格沒有寫一個腳手架更值得炫耀),如果不會寫可以問問 AI。

而當你真正開始封裝元件,開始寫工具庫了,你會發現你需要思考的確實比之前多了。

關注業務

對於前端業務重要嗎?

相比於後端來說,前端一般不會太關注業務。就算出了問題大部分也是後端的問題。

但是就我找工作的經驗,業務非常重要!

如果你做的工作很有技術含量,比如你在做低程式碼,你可以面試時講一個小時的技術難點。但是你只是一個破寫後臺管理,你什麼都沒有的說。這個時候,瞭解業務就成為了你的亮點。

一場面試

還是拿真實的面試場景舉例,當時前同事推我位元組,也是我面試過N次的夢中情廠了,剛好那個組做的業務和我之前呆的組做的一模一樣。

  • 同事:“做的東西和咱們之前都是一樣的,你隨便走個過場就能過,我在前端組長面前都誇過你了!”
  • 我:“好嘞!”

等到面試的時候:

  • 前端ld:“你知道xxx嗎?(業務名詞)”
  • 我:“我……”
  • 前端ld:“那xxxx呢?(業務名詞)”
  • 我:“不……”
  • 前端ld:“那xxxxx呢??(業務名詞)”
  • 我:“造……”

然後我就掛了………………

如何瞭解業務

  1. 每次接需求的時候,都要了解需求背景,並主動去理解

    我們寫一個表格簡簡單單,把資料展示出來就好,但是表格中的資料是什麼意思呢?比如我之前寫一個 kafka 管理平臺,裡面有表格表單,涉及什麼 cluster controller topic broker partition…… 我真的完全不瞭解,很後悔我幾年時間也沒有耐下心來去了解。

  2. 每次做完一個需求,都需要了解結果

    有些時候,後臺管理的團隊可能根本沒有PM,那你也要和業務方瞭解,這個功能做了之後,多少人使用,效率提高了嗎?資料是怎樣的?

  3. 理解需求,並主動去最佳化

    產品要展示一千條資料,你要考慮要不要分頁,不分頁會不會卡,要不要上虛擬表格?

    產品要做一個可拖拽表單,你要考慮是否需要拖動,是否需要配置。

    其實很多時候,產品的思維可能會被侷限在競品的實現方式,而前端可以給TA更多選項。在和產品溝通的時候,你不僅是溝通頁面的實現,也更能理解業務。

關注原始碼

說到原始碼, Vue,React 這些基本是每次必問,也有太多大佬們的總結我就不多說了。

除此之外,我想大家每次面試應該都會被問,你寫了什麼亮點的專案,困難的專案,你會說什麼?哦,都是表單表格,都用 Element UI 實現的,沒什麼難度。那估計你面試也就到這裡了。

那說什麼,後臺管理就這些啊?!

如果你用了 Element UI 你可以說寫了什麼自定義 Element UI 表單元件,Element UI 表單原始碼是什麼原理,怎麼通訊的?用了 Axios 可以說 Axios 的原理,它的攔截器怎麼實現的?用了編輯器 diff 那你知道 diff 演算法是什麼嗎?用了 ECharts 那你知道他底層是用什麼繪製的嗎?用了 husky ?husky的原理是什麼?用了Vite,它為什麼快?是怎麼打包的?寫過外掛嗎?

可能有人覺得我離譜,事實上上面每一個問題都是我在面試中真實被問到的。當然,如果全部去了解,肯定不現實,每個人的精力有限,不可能每個用到的每個工具每個庫都去了解原理,不過只要有一兩個你去了解過,就可以在面試中引導面試官來問,要學會表現出你擅長的點

至於怎麼讀原始碼?以前我不知道,現在嘛…… 為什麼不問問神奇的 ChatGPT 呢?

講一下 Axios 原始碼中,攔截器是怎麼實現的?

Axios 的攔截器實現基於 Axios 的核心原理,即 Axios 例項是一個包含請求和響應攔截器堆疊的物件。當發出請求或接收響應時,Axios 會遍歷這些攔截器,並按照新增的順序執行請求攔截器,以及按照相反的順序執行響應攔截器。

在 Axios 的原始碼中,攔截器是透過一個 AxiosInterceptorManager 例項來管理的,它維護了一個攔截器陣列。每個攔截器都是一個包含 fulfilledrejected 函式的物件。這兩個函式分別對應於攔截器成功處理和攔截器處理出錯的情況。

以下是 Axios 攔截器管理器的一個簡化版本,展示了其核心實現思路:

class InterceptorManager {
  constructor() {
    this.handlers = []; // 儲存攔截器的陣列
  }

  use(fulfilled, rejected) {
    this.handlers.push({
      fulfilled: fulfilled,
      rejected: rejected
    });
    return this.handlers.length - 1; // 返回攔截器的ID
  }

  eject(id) {
    if (this.handlers[id]) {
      this.handlers[id] = null; // 移除攔截器
    }
  }

  forEach(fn) {
    this.handlers.forEach((h) => {
      if (h !== null) {
        fn(h);
      }
    });
  }
}

在傳送請求或接收響應時,Axios 會建立一個 promise 鏈,並透過 forEach 方法將攔截器中的 fulfilledrejected 函式新增到這個鏈中。這樣,每個攔截器都可以對請求或響應進行處理,然後將結果傳遞到鏈的下一個攔截器,或者在出錯時結束鏈的執行。

axios.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
  chain.unshift(interceptor.fulfilled, interceptor.rejected);
});

axios.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
  chain.push(interceptor.fulfilled, interceptor.rejected);
});

在 Axios 的完整實現中,這個攔截器機制被整合到了 Axios 的請求傳送和響應處理流程中。透過這種方式,Axios 可以在傳送請求之前和接收響應之後,但在使用者定義的 .then.catch 執行之前,插入自定義的邏輯。

請注意,這裡提供的程式碼只是為了說明 Axios 攔截器的實現原理,並不是 Axios 原始碼的完整複製。如果你對 Axios 的攔截器實現細節感興趣,建議檢視 Axios 的官方 GitHub 倉庫中的原始碼。

前端基建

當我們工作時間久了面試難免會遇到這些問題,前端工程化,前端監控,工作流,部署,效能等等。其實我們在工作中絕大部分時間都在寫程式碼,對於這些不是所有人都有機會接觸到,不過這些和所做的業務無關,是我們提升自己很好的一個思路。

技術選型

技術棧選 Vue 還是 React?Vue 選 Vue2 還是 Vue3?元件庫選 ElementUI 還是 Ant Design?微前端有沒有使用過?打包工具用 Vite 還是 Webpack?有那麼多表單怎麼實現的,有沒有什麼表達配置化方案,比如Formily?

對於我這種菜雞,我這種只寫簡單的表單表格的人,這些都……無所謂……

不過為了應對面試我們還是需要了解下未選擇技術棧的缺點,和已選擇技術棧的優點(有點本末倒置…但是常規操作啦)

Vue 你可以說簡單高效輕量級,面試必會問你為什麼,你就開始說 Vue 的響應式系統,依賴收集等。

React 你可以說 JSX、Hooks 很靈活,那你必然要考慮 JSX 怎麼編譯, Hooks 實現方式等。

總體而言,對於技術選型,依賴於我們對所有可選項的理解,做選擇可能很容易,給出合理的理由還是需要花費一些精力的。

開發規範

這個方面,在面試的時候我被問到的不多,我們可以在建立專案的時候,配置下 ESlintstylelintprettiercommitlint 等。

前端監控

幹了這麼多年前端,前端監控我是……一點沒做過。

前端監控,簡單來說就是我們在前端程式中記錄一些資訊並上報,一般是錯誤資訊,來方便我們及時發現問題並解決問題。除此之外也會有效能監控,使用者行為的監控(埋點)等。之前也聽過有些團隊分享前端監控,為了出現問題明確責任(方便甩鍋)。

對於實現方案,無論使用第三方庫還是自己實現,重要的都是理解實現原理。

對於錯誤監控,可以瞭解一下 Sentry,原理簡單來說就是透過 window.onerrorwindow.addEventListener('unhandledrejection', ...) 去分別捕獲同步和非同步錯誤,然後透過錯誤資訊和 sourceMap 來定位到原始碼。

對於效能監控,我們可以透過 window.performancePerformanceObserver 等 API 收集頁面效能相關的指標,除此之外,還需要關注介面的響應時間。

最後,收集到資訊之後,還要考慮資料上報的方案,比如使用 navigator.sendBeacon 還是 Fetch、AJAX?是批次上報,實時上報,還是延遲上報?上報的資料格式等等。

CI/CD

持續整合(Continuous Integration, CI)和 持續部署(Continuous Deployment, CD),主要包括版本控制,程式碼合併,構建,單測,部署等一系列前端工作流。

場景的工作流有 Jenkins、 Gitlab CI 等。我們可以配置在合併程式碼時自動打包部署,在提交程式碼時自動構建併發布包等。

這塊我瞭解不多,但感覺這些工具層面的東西,不太會涉及到原理,基本上就是使用的問題。還是需要自己親自動手試一下,才能知道細節。比如在 Gitlab CI 中, PipelineStageJob 分別是什麼,怎麼配置,如何在不同環境配置不同工作流等。

瞭解技術動態

這個可能還是比較依賴資訊收集能力,雖然我個人覺得很煩,但好像很多領導級別的面試很願意問。

比如近幾年很火的低程式碼,很多面試官都會問,你用過就問你細節,你沒用過也會問你有什麼設計思路。

還有最近的兩年爆火的 AI,又或者 Vue React的最新功能,WebAssembly,還有一些新的打包工具 Vite Bun 什麼的,還有鴻蒙開發……

雖然不可能學完每一項新技術,但是可以多去了解下。

總結

寫了這麼多,可能有人會問,如果能回到過去,你會怎麼做。

啊,我只能說,說是一回事,做又是另一回事,事實上我並不希望回到過去去卷一遍,菜點沒關係,快樂就好,一切都是最好的安排。

相關文章