本文是深入浅出 ahooks 源码系列文章的第八篇,该系列已整顿成文档 - 地址。感觉还不错,给个 star 反对一下哈,Thanks。
本篇文章算是该系列的一个彩蛋篇,记录一下第一次给开源我的项目提 PR 的过程(之前如同也有过,不过那个十分小的一个改变),心愿可能帮忙更多的人参加到开源我的项目中来。
起因
在写了几篇对于 ahooks 的文章之后,收到了官网同学的私信。
这让我受宠若惊的同时也有点小兴奋和惶恐。
兴奋是,之前感觉参加开源是一件遥不可及的事件,当初仿佛我也可能去做了。当然也有公心,如果我的简历上有给开源我的项目做奉献的经验,那岂不是一个不错的加分项?
惶恐的是,我之前没有参加过开源我的项目,放心本人不能做好这件事。
依据大佬的倡议,我决定先从一些 issue 动手,也就是帮忙解决一下 issue。
明确问题 OR 需要
于是我抱着试试看的态度,看了一下官网的 issue,看到这么一条。issue 详情。
刚好我之前对 useRequest 源码做过一些剖析——如何应用插件化机制优雅的封装你的申请。于是我决定 fix 一下这个 issue。
这个 issue 的需要很简略,就是心愿轮询失败后,可能反对最大的轮询次数,如果失败的次数大于这个值,则进行轮询。
编码前筹备
首先,从 ahooks 官网 GitHub 中 folk 一份。这个操作我之前曾经做了。
第二步,基于 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
上述都实现之后,就能够提交你的代码了,提交完,去到在你 folk 过去的我的项目中,能够看到这个。
咱们须要点击图中框起来的「Compare & pull request」,之后就会呈现如下图
默认会帮咱们选好分支的,咱们只须要欠缺其中的信息,还有咱们之前提交的 message 也能够批改。最好能够用英文来解释,本次提交的内容。
最初点击提交之后就好了。
还有一个提 PR 的入口,如下所示:
最初期待官网 CR 就能够了(下面的实现其实局部是 CR 后改的)。目前该 PR 曾经被合入到 master。
总结思考
给开源我的项目提 PR 操作过程 不是一件很简单的事件,重点在于需要的批改。往往须要思考到多种边界场景,这个时候,咱们就须要前端的单元测试来帮忙咱们笼罩全面的场景。
另外,对于一些还没有参加开源我的项目教训的同学来讲,我感觉相似 ahooks 这种工具库是一个不错的抉择:
- 它的模块划分更加清晰,你改了一个模块的性能,影响面能够更好的预估。对新人比拟敌对。
- 逻辑绝对简略,其实你会发现很多代码说不定在你们的业务我的项目中的 utils/hooks 文件夹中就有。
- 社区比拟沉闷,维护者可能较快的响应。
心愿对大家有所帮忙。