前言
- 本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
- 这是源码共读的第18期,链接:第18期 | delay 带取消功能的延迟函数
从delay 源码学习延迟函数
- 源码仓库:delay
- 源码地址:delay/idnex.js
代码结构
const createDelay = ({ clearTimeout: defaultClear, setTimeout: set, willResolve }) => (ms, { value, signal } = {}) => {
// ...逻辑封装
const delayPromise = new Promise((resolve, reject) => {
// ...创建Delay本体
}
return delayPromise;
}
const createWithTimers = (clearAndSet) => {
const delay = createDelay({ ...clearAndSet, willResolve: true });
delay.reject = createDelay({ ...clearAndSet, willResolve: false });
delay.range = (minimum, maximum, options) =>
delay(randomInteger(minimum, maximum), options);
return delay;
};
// 生成delay函数
const delay = createWithTimers();
delay.createWithTimers = createWithTimers;
module.exports = delay;
// TODO: Remove this for the next major release
module.exports.default = delay;
randomInteger 设置区间随机数
const randomInteger = (minimum, maximum) => Math.floor((Math.random() * (maximum - minimum + 1)) + minimum);
createAbortError 错误结构构造函数
const createAbortError = () => {
const error = new Error('Delay aborted');
error.name = 'AbortError';
return error;
};
createDelay Delay构造函数
const createDelay = ({clearTimeout: defaultClear, setTimeout: set, willResolve}) => (ms, {value, signal} = {}) => {
if (signal && signal.aborted) {
return Promise.reject(createAbortError());
}
let timeoutId;
let settle;
let rejectFn;
const clear = defaultClear || clearTimeout;
// 控制器中止行为
const signalListener = () => {
clear(timeoutId);
rejectFn(createAbortError());
};
// 清除控制器Listener
const cleanup = () => {
if (signal) {
signal.removeEventListener('abort', signalListener);
}
};
// 创建Delay本体
const delayPromise = new Promise((resolve, reject) => {
// 延时事件本体
settle = () => {
cleanup();
if (willResolve) {
resolve(value);
} else {
reject(value);
}
};
rejectFn = reject;
// 注册延时事件
timeoutId = (set || setTimeout)(settle, ms);
});
// 控制器Listener
if (signal) {
signal.addEventListener('abort', signalListener, {once: true});
}
// 挂载clear函数
delayPromise.clear = () => {
// 清除延时
clear(timeoutId);
timeoutId = null;
// 调用事件本体,设置Promise状态
settle();
};
return delayPromise;
};
createWithTimers 创建delay函数
// 构造delay函数
const createWithTimers = clearAndSet => {
const delay = createDelay({...clearAndSet, willResolve: true});
delay.reject = createDelay({...clearAndSet, willResolve: false});
delay.range = (minimum, maximum, options) => delay(randomInteger(minimum, maximum), options);
return delay;
};
总结
delay这个库代码不多,核心流程是
delay函数接受一个延时时间和一个成功要返回的数据并返回一个Promise,通过setTimeout来延时设置Promise的状态完成异步等待Promise挂载clear函数,该函数可以中止延时并将Promise状态设置为创建delay默认想要的状态delay默认Promise的状态(willResolve)是truedelay.reject默认Promise的状态(willResolve)是false- 提供一个
delay.range可以在一个时间区间内随机一个时间来做异步
从核心流程来看,有几个缺点,而delay这个库也都完善了
delay的Promise默认是fulfilled一旦设定后无法改变所以入参支持传入控制器 signal ,可以通过signal来中断延时并设置Promise为失败setTimeout和clearTimeout可能需要执行其他任务,所以createDelay也支持外部自定义setTimeout和clearTimeout