天天看點

記錄第一次給開源項目提 PR

本文是深入淺出 ahooks 源碼系列文章的第八篇,該系列已整理成文檔-位址。覺得還不錯,給個 star 支援一下哈,Thanks。

本篇文章算是該系列的一個彩蛋篇,記錄一下第一次給開源項目提 PR 的過程(之前好像也有過,不過那個非常小的一個改動),希望能夠幫助更多的人參與到開源項目中來。

起因

在寫了幾篇關于 ahooks 的文章之後,收到了官方同學的私信。

記錄第一次給開源項目提 PR

這讓我受寵若驚的同時也有點小興奮和惶恐。

興奮是,之前感覺參與開源是一件遙不可及的事情,現在似乎我也能夠去做了。當然也有私心,假如我的履歷上有給開源項目做貢獻的經曆,那豈不是一個不錯的加分項?

惶恐的是,我之前沒有參與過開源項目,擔心自己不能做好這件事。

根據大佬的建議,我決定先從一些 issue 入手,也就是幫忙解決一下 issue。

明确問題OR需求

于是我抱着試試看的态度,看了一下官方的 issue,看到這麼一條。issue 詳情。

記錄第一次給開源項目提 PR

剛好我之前對 useRequest 源碼做過一些分析——如何使用插件化機制優雅的封裝你的請求。于是我決定 fix 一下這個 issue。

這個 issue 的需求很簡單,就是希望輪詢失敗後,能夠支援最大的輪詢次數,假如失敗的次數大于這個值,則停止輪詢。

編碼前準備

首先,從 ahooks 官方 GitHub 中 folk 一份。這個操作我之前已經做了。

記錄第一次給開源項目提 PR

第二步,基于 master 切換一個功能分支。如下:

git checkout -b fix/pollingSupportRetryCount
           

最後就是環境的一些初始化操作,不同的倉庫不同,ahooks 如下:

yarn run init
yarn start
           

功能實作

我們先來看下現在 useRequest 的輪詢的實作,其原理主要是在一個請求結束的時候(不管成功與失敗),通過 setTimeout 進行重新請求,達到輪詢的效果。

onFinally: () => {
  // 省略部分代碼...
  // 通過 setTimeout 進行輪詢
  timerRef.current = setTimeout(() => {
    fetchInstance.refresh();
  }, pollingInterval);
},
           

我的想法是,定義一個 options 參數,

pollingErrorRetryCount

,預設為 -1,代表沒有限制。

另外定義一個變量,記錄目前重試的次數:

const countRef = useRef<number>(0);
           

當開發者設定了 pollingErrorRetryCount,并且重試的數量大于該值,我們就直接傳回,不執行輪詢的邏輯。

當成功或者失敗的時候,更新目前重試的次數:

onError: () => {
  countRef.current += 1;
},
onSuccess: () => {
  countRef.current = 0;
},
           

然後在請求結束的時候,判斷重試的次數有沒有達到了開發設定的次數,假如沒有則執行重試操作。有則重置重試的次數,停止輪詢。

onFinally: () => {
  if (
    pollingErrorRetryCount === -1 ||
    // When an error occurs, the request is not repeated after pollingErrorRetryCount retries
    (pollingErrorRetryCount !== -1 && countRef.current <= pollingErrorRetryCount)
  ) {
    // 忽略部分代碼
    timerRef.current = setTimeout(() => {
      fetchInstance.refresh();
    }, pollingInterval);
  } else {
    countRef.current = 0;
  }
},
           

測試用例

上述整體的改造并不困難,但是我在寫測試用例的時候,就開始踩坑了,因為我很少書寫前端的測試用例,還是針對于 hooks 的測試用例。這裡是我耗時最多的地方。

最終用例如下:

// 省略部分代碼...
// if request error and set pollingErrorRetryCount
// and the number of consecutive failures exceeds pollingErrorRetryCount, polling stops
let hook2;
let errorCallback;
act(() => {
  errorCallback = jest.fn();
  hook2 = setUp(() => request(0), {
    pollingErrorRetryCount: 3,
    pollingInterval: 100,
    pollingWhenHidden: true,
    onError: errorCallback,
  });
});

expect(hook2.result.current.loading).toEqual(true);
expect(errorCallback).toHaveBeenCalledTimes(0);

act(() => {
  jest.runAllTimers();
});
await hook2.waitForNextUpdate();
expect(hook2.result.current.loading).toEqual(false);
expect(errorCallback).toHaveBeenCalledTimes(1);

act(() => {
  jest.runAllTimers();
});
await hook2.waitForNextUpdate();
expect(errorCallback).toHaveBeenCalledTimes(2);

act(() => {
  jest.runAllTimers();
});
await hook2.waitForNextUpdate();
expect(errorCallback).toHaveBeenCalledTimes(3);

act(() => {
  jest.runAllTimers();
});
await hook2.waitForNextUpdate();
expect(errorCallback).toHaveBeenCalledTimes(4);

act(() => {
  jest.runAllTimers();
});
expect(errorCallback).toHaveBeenCalledTimes(4);

act(() => {
  hook2.result.current.run();
});
act(() => {
  jest.runAllTimers();
});
await hook2.waitForNextUpdate();
expect(errorCallback).toHaveBeenCalledTimes(5);

hook2.unmount();
// 省略部分代碼...
           

大緻解釋下該測試用例的邏輯,我設定了重試三次,錯誤之後,運作了三次,

errorCallback

就會被調用了 4 次(包括錯誤那次)。在第五次執行的時候,就不會執行

errorCallback

,也就還是 4 次。然後我們手動 run 一次請求,期待

errorCallback

應該執行 5 次。

這裡踩了一個坑,就是第五次請求的時候,我之前是會寫一個等待定時器執行的操作,但實際上這裡它是不會執行定時器的,導緻一直報錯,在這裡折騰了很久。後來删除了下面的代碼才執行成功。

act(() => {
  jest.runAllTimers();
});
- await hook2.waitForNextUpdate();
expect(errorCallback).toHaveBeenCalledTimes(4);
           

文檔以及 Demo 補充

畢竟加了一個新的 API 參數,需要在文檔中注明,而且中英文文檔都需要補充,還加上了一個 Demo 示例。

記錄第一次給開源項目提 PR
記錄第一次給開源項目提 PR

提 PR

上述都完成之後,就可以送出你的代碼了,送出完,去到在你 folk 過來的項目中,可以看到這個。

記錄第一次給開源項目提 PR

我們需要點選圖中框起來的「Compare & pull request 」,之後就會出現如下圖

記錄第一次給開源項目提 PR

預設會幫我們選好分支的,我們隻需要完善其中的資訊,還有我們之前送出的 message 也可以修改。最好可以用英文來解釋,本次送出的内容。

最後點選送出之後就好了。

還有一個提 PR 的入口,如下所示:

記錄第一次給開源項目提 PR

最後等待官方 CR 就可以了(上面的實作其實部分是 CR 後改的)。目前該 PR 已經被合入到 master。

總結思考

給開源項目提 PR 操作過程不是一件很複雜的事情,重點在于需求的修改。往往需要考慮到多種邊界場景,這個時候,我們就需要前端的單元測試來幫助我們覆寫全面的場景。

另外,對于一些還沒有參與開源項目經驗的同學來講,我覺得類似 ahooks 這種工具庫是一個不錯的選擇:

  • 它的子產品劃分更加清晰,你改了一個子產品的功能,影響面可以更好的預估。對新人比較友好。
  • 邏輯相對簡單,其實你會發現很多代碼說不定在你們的業務項目中的 utils/hooks 檔案夾中就有。
  • 社群比較活躍,維護者能夠較快的響應。

希望對大家有所幫助。

繼續閱讀