优秀 npm package 收集及解读

514 阅读5分钟
  • 类型判断或检测相关
    • is-type-of 检测数据类型,引用了 core-util-isis-classis-stream
      const is = require('is-type-of');
      
    • core-util-is 判断数据类型
      function fn (a, b){
        console.log(Array.isArray(arguments)); // false
        console.log(Object.prototype.toString.call(arguments)); // [object Arguments]
      }
      fn(1, 2);
      
      /* 核心源码摘要及解读 */
      // 判断是否 undefined
      function isUndefined(arg) {
        return arg === void 0;
      }
      // 判断是否 undefined 或 null
      function iNullOrUndefined(arg) { 
        return arg == null;
      }
      // 判断是否对象
      function isObject(arg) {
        // typeof null; => "object"
        return typeof arg === 'object' && arg !== null;
      }
      // 判断是否为数组
      function isArray(arg) {
        if(Array.isArray) {
          return Array.isArray(arg);
        }
        return objectToString(arg) === '[object Array]';
      }
      // 是否为 Buffer
      exports.isBuffer = Buffer.isBuffer;
      // 判断是否为基本类型
      function isPrimitive(arg) {
        return arg === null ||
               typeof arg === 'boolean' ||
               typeof arg === 'number' ||
               typeof arg === 'string' ||
               typeof arg === 'symbol' ||  // ES6 symbol
               typeof arg === 'undefined';
      }
      // 判断是否为 Error
      function isError(e) {
        return (objectToString(e) === '[object Error]' || e instanceof Error);
      }
      // 核心方法,返回 [object Object] 形式的结果,可以判断出 Boolean、String、Number、Undefined、Null、Symbol、Object、Array、Date、RegExp等等,可以通过Symbole.toStringTag 改写默认返回
      function objectToString(o) {
        return Object.prototype.toString.call(o);
      }
      
    • is-stream 检测数据是否为 stream 类型
      const isStream, { isReadable, isWritable, isDuplex } = require('isstream');
      
      /* 核心源码摘要及解读 */
      var stream = require('stream');
      function isStream(obj) {
        // stream.Stream 是一个类
        return obj instanceof stream.Stream;
      }
      function isReadable(obj) {
        // Readable 类型的 stream 必须要实现 _read 方法 和 _readableState 属性
        return isStream(obj) && typeof obj._read === 'function' && typeof obj._readableState === 'object';
      }
      function isWritable(obj) {
        // Readable 类型的 stream 必须要实现 _write 方法 和 _writeableState 属性
        return isStream(obj) && typeof obj._write === 'function' && typeof obj._writeableState === 'object';
      }
      function isDuplex(obj) {
        return isReadbale(obj) && isWritable(obj);
      }
      
    • is-class 检测函数是否为 ES6 class
      const is = require('is-type-of');
      
      /* 核心源码摘要及解读 */
      // 采用自执行函数闭包形式,对外暴露出 isClass 函数
      (function(root) {
        // 缓存在作用域中,减少 toString 方法的查找时间
        var toString = Function.prototype.toString;
          // 截取出 class 中 body 部分
        function fnBody(fn) {
          return toString.call(fn).replace(/^[^{]*{\s*/,'').replace(/\s*}[^}]*$/,'');
        }
        // 判断函数是否为 class
        // class cls {} 经过babel 转译后 https://babeljs.io/repl/
        /*
          'use strict';
          function _classCallCheck(instance, Constructor) {
            if (!(instance instanceof Constructor)) {
              throw new TypeError('Cannot call a class as a function');
            }
          }
          var cls = function cls() {
            _classCallCheck(this, cls);
          }
        */
        function isClass(fn) {
          return (typeof fn === 'function' &&
                  (/^class\s/.test(toString.call(fn)) ||
                    (/^.*classCallCheck\(/.test(fnBody(fn)))) // babel 转译
                  );
        }
        if (typeof exports !== 'undefined') { // 支持 CommonJS 环境
          if (typeof module !== 'undefined' && module.exports) {
            exports = module.exports = isClass;
          }
          exports.isClass = isClass;
        } else if (typeof define === 'function' && define.amd) { // 支持 AMD 环境
          define([], function() {
            return isClass;  
          })
        } else {
          root isClass = isClass;
        }
      })(this); // 浏览器中 this 指向 window(非严格模式), node中指向 global
      
    • is-generator-function 判断是否为 generator 函数
    /* 源码摘要及解读 */
    var toStr = Object.prototype.toString;
    var fnToStr = Function.prototype.toString;
    var isFnRegex = /\s*(?:function)?\*/;
    // 判断引擎是否有 Symbol 及其属性 toStringTag(Object.prototype.toString 隐式调用此属性)
    var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
    // 生成最简化的 generator 函数
    var getGeneratorFunc = function () {
      // 判断引擎是否有 Symbol 和 Symbol.toStringTag
      if (!hasToStringTag) {
        return false;
      }
      try {
        return Function('return function*() {}')();
      } catch(e) {
      }
    }
    var generatorFunc = getGeneratorFunc(); // f* () {}
    // 获取 generator 函数原型属性/方法
    var GeneratorFunction = generatorFunc ? getProto(generatorFunc) : {}; // GeneratorFunction {prototype: Generator, Symbol(Symbol.toStringTag}: "GeneratorFunction", constructor: f}
    module.exports = function isGeneratorFunction(fn) {
      if (typeof fn !== 'function') {
        return false;
      }
      // 将函数体toSting fnToStr.call(fn) => "function* (){}"
      // isFnRegex.test() 正则判断函数是否为 generator 型
      if (isFnRegex.test(fnToStr.call(fn)) {
        return true;
      }
      // 引擎未部署 Symbol 和 Symbol.toStringTag
      if (!hasToStringTag) {
        var str = toStr.call(fn);
        return str === '[object GeneratorFunction]';
      }
      return getProto(fn) === GeneratorFunction;
    }
    
  • 属性/方法注入相关
    • get-ready 为对象注册一个 ready 方法
      const ready = require('get-ready');
      const obj = {};
      ready.mixin(obj);
      // register a callback
      obj.ready(() => console.log('ready'));
      // mark ready
      obj.ready(true);
      
    • merge-descriptors 合并对象属性/方法
      /* 核心代码摘要及解读 */
      // 缓存 hasOwnProperty 方法
      var hasOwnProperty = Object.prototype.hasOwnProperty;
      function merge(dest, src, redefine) {
        // 参数判断...
        // 取出自有属性(不包括 Symbol 属性)
        Object.getOwnPropertyNames(src).forEach(function forEachOwnPropertyName(name) {
          // redefine 默认 true
          // 只合并自有属性,不包括原型上的
          if (!redefine && hasOwnProperty.call(dest, name)) {
            return
          }
          // 拷贝descriptor
          var descriptor = Object.getOwnPropertyDescriptor(src, name)
          Object.defineProperty(dest, name, descriptor)
        })
        return dest
      }
      
    • utils-merge 合并对象
  • HTTP 相关
    • detect-port 检查端口是否被占用
    • type-is
    • body-parser 解析json、raw、text、url-encodeed格式的http request body
      // parse 'application/x-www-form-urlencoded'
      // parse 'application/json'
      // parse various different custom JSON types as JSON, 'application/*+json'
      // parse 'application/vnd.custom-type'
      // parse 'text/html'
      
    • proxy-addr
    • cookie-signature
    • cookie
    • http-errors
    • on-finished
    • statuses HTTP 状态工具库
    • raw-body
    • http-assert
    • delegates
    • content-type
    • content-disposition
    • mime-types content-type 工具
    • negotiator 内容协商
    • methods http 请求方法列表
      /* 核心代码摘要及解读 */
      var http = require('http')
      module.exports = getCurrentNodeMethods() || getBasicNodeMethods();
      function getCurrentNodeMethods() {
        return http.METHODS && http.METHODS.map(function lowerCaseMethod(method) {
          return method.toLowerCase()
        })
      }
      function getBasicNodeMethods () {
        return ['get', 'post', 'put','head','delete','options','trace','copy','lock','mkcol','move','purge','propfind','proppatch','unlock','report','mkactivity','checkout','merge','m-search','notify', 'subscribe', 'unsubscribe', 'patch','search','connect']
      }
      
    • accepts
    • fresh 判断 http 缓存是否过期
    • range-parser
    • parseurl 解析url
    • send
    • vary 处理 http vary header
    • method-override
    • forwarded 解析 Header:X-Forward-For
    • ipaddr.js
  • 系统相关
    • address 获得本机 IP 和 MAC 地址
    • cfork fork 子进程和重启
      const uitl = require('util');
      const cfork = require('cfork');
      cfork({
        exec: '/your/app/worker.js',
        // slaves: ['/your/app/worker.js'],
        // count: require('os').cpus().length
      })
      .on('fork', woker => {
        console.warn('[%s] [worker:%d] new worker start', Date(), worker.process.pid);
      })
      .on('disconnect', worker => {
        console.warn('[%s] [master:%s] worker:%s disconnect, exitedAfterDisconnect: %s, state: %s.', Date(), process.pid, worker.process.pid, worker.exitedAfterDisconnect, worker.state);
      })
      .on('exit', (worker, code, signal) => {
        const err = new Error(util.format('worker %s died (code: %s, signal: %s, exitedAfterDisconnect: %s, state: %s)',
          worker.process.pid, exitCode, signal, worker.exitedAfterDisconnect, worker.state));
        err.name = 'WorkerDiedError';
        console.error('[%s] [master:%s] wroker exit: %s', Date(), process.pid, err.stack);
      });
      .on('unexpectedExit', (worker, code, signal) => {
      })
      .on('reachReforkLimit', () => {
      });
      process.on('uncuaghtException', err => {
      });
      
    • cluster-reload 重启子进程
    • graceful 进程优雅的退出
  • 时间类相关
    • humanize-ms 将时间转为毫秒数
    • ms 将时间转为毫秒数
  • polyfill 相关
    • setprototypeof Object.setPrototypeOf 的 polyfill
      /* 核心代码摘要及解读 */
      module.exports = Object.setPrototypeOf || ({__proto__: []} instanceof Array ? setProtoOf : minxinProperties);
      function setProtoOf(obj, proto) {
        obj.__proto__ = proto;
        return obj;
      }
      function mixinProperties(obj, proto) {
        for (var prop in obj) {
          if (!obj.hasOwnProperty(prop)) {
            obj[prop] = proto[prop];
          }
        }
        return obj;
      }
      
    • inherits 继承,node.js 直接使用 util.inherits,提供浏览器端 shim
    • object-assign
  • 内容处理相关
  • 数组处理相关
  • 调试相关
  • 错误处理相关
  • koa 框架相关
  • 文件处理
  • 函数相关
  • after
  • 测试相关