delay 源码学习

125 阅读2分钟

前言

从delay 源码学习延迟函数

代码结构

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这个库代码不多,核心流程是

  1. delay函数接受一个延时时间和一个成功要返回的数据并返回一个Promise,通过setTimeout来延时设置Promise的状态完成异步等待
  2. Promise挂载 clear 函数,该函数可以中止延时并将Promise状态设置为创建delay默认想要的状态
  3. delay默认Promise的状态(willResolve)是 true
  4. delay.reject 默认Promise的状态(willResolve)是 false
  5. 提供一个delay.range 可以在一个时间区间内随机一个时间来做异步

从核心流程来看,有几个缺点,而delay这个库也都完善了

  1. delayPromise 默认是 fulfilled 一旦设定后无法改变所以入参支持传入控制器 signal ,可以通过 signal 来中断延时并设置 Promise 为失败
  2. setTimeoutclearTimeout 可能需要执行其他任务,所以 createDelay 也支持外部自定义 setTimeoutclearTimeout