npm-modules

deplay

带取消功能的延迟函数

参考好文:

目标

作用

delay 用法

const delay = require('delay');

(async () => {
  bar();

  await delay(100);

  // Executed 100 milliseconds later
  baz();
})();

以前有用到一个 sleep, 跟这个有点类似

const sleep = (ms, data) => new Promise((resolve) => setTimeout(resolve, ms, data));

// 等效如下
function sleep2(ms, data) {
  return new Promise((resolve, reject) => {
    setTimeout((d) => {
      resolve(d)
    }, ms, data)
  })
}

// testing
sleep(3000, {code: 0}).then(res => {
  console.log(res)
});
console.log(111);
// 扩展
// 2. 传入 value 作为返回值
// 3. 通过参数控制返回 resolve or reject
// 4. 一定时间范围内随机获得结果
// 5. 支持提前清除
const randomInteger = (minimum, maximum) => Math.floor((Math.random() * (maximum - minimum + 1)) + minimum);

const createDelay = ({willResolve}) => (ms, {value} = {}) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if(willResolve){
        resolve(value);
      }
      else{
        reject(value);
      }
    }, ms);
  });
}

const createWithTimers = () => {
  const delay = createDelay({willResolve: true});
  delay.reject = createDelay({willResolve: false});
  delay.range = (minimum, maximum, options) => delay(randomInteger(minimum, maximum), options);
  return delay;
}

// testing
const delay4 = createWithTimers();

源码分析

'use strict';

// From https://github.com/sindresorhus/random-int/blob/c37741b56f76b9160b0b63dae4e9c64875128146/index.js#L13-L15
const randomInteger = (minimum, maximum) => Math.floor((Math.random() * (maximum - minimum + 1)) + minimum);

const createAbortError = () => {
  const error = new Error('Delay aborted');
  error.name = 'AbortError';
  return error;
};

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());
  };

  const cleanup = () => {
    if (signal) {
      signal.removeEventListener('abort', signalListener);
    }
  };

  const delayPromise = new Promise((resolve, reject) => {
    settle = () => {
      cleanup();
      if (willResolve) {
        resolve(value);
      } else {
        reject(value);
      }
    };

    rejectFn = reject;
    timeoutId = (set || setTimeout)(settle, ms);
  });

  if (signal) {
    signal.addEventListener('abort', signalListener, {once: true});
  }

  delayPromise.clear = () => {
    clear(timeoutId);
    timeoutId = null;
    settle();
  };

  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;
};

const delay = createWithTimers();
delay.createWithTimers = createWithTimers;

module.exports = delay;
// TODO: Remove this for the next major release
module.exports.default = delay;

知识点