優秀 npm package 收集及解讀

jedi_knight發表於2017-11-21
  • 型別判斷或檢測相關
    • 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
  • 測試相關

相關文章