npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

qyh_utils

v1.0.26

Published

公共方法工具库

Readme

安装

$ npm i qyh_utils

EventBus

import {EventBus} from "qyh_utils"
const emmiter=new EventBus()
// 监听事件
emitter.on('foo', e => console.log('foo', e) )

// 派发事件
emitter.emit('foo', { a: 'b' })

// 清除所有事件
emitter.off()

// 清除同名事件
emitter.off("foo")

// 清除指定事件
emitter.off("foo",onFoo)

Typescript

interface Events {
  foo: string
  bar?: number
}
const emitter = new EventBus<Events>()

emitter.on('foo', (e) => {}) // 'e' has inferred type 'string'

emitter.emit('foo', 42) // Error: Argument of type 'number' is not assignable to parameter of type 'string'. (2345)

ImageCompressor

import {ImageCompressor} from "qyh_utils"
import type {ImageCompressorOptions,IFile} from "qyh_utils"

const options:ImageCompressorOptions = {
  file: file,
  quality: 0.6,
  mimeType: 'image/jpeg',
  maxWidth: 500,
  maxHeight: 500,
  width: 200,
  height: 200,
  minWidth: 100,
  minHeight: 100,
  convertSize: Infinity,
  loose: true,
  redressOrientation: true,
  // 图片绘画前
  beforeDraw: function (ctx:CanvasRenderingContext2D) {
    console.log('准备绘图...');
    ctx.filter = 'grayscale(100%)';
  },

  // 图片绘画后
  afterDraw: function (ctx:CanvasRenderingContext2D, canvas:HTMLCanvasElement) {
    ctx.restore();
    console.log('绘图完成...');
    ctx.fillStyle = '#fff';
    ctx.font = (canvas.width * 0.1) + 'px microsoft yahei';
    ctx.fillText("qyh", 10, canvas.height - 20);
  },
  // 压缩前回调
  beforeCompress: function (result:IFile) {
    console.log('压缩之前图片尺寸大小: ', result.size);
    console.log('mime 类型: ', result.type);
  },

  // 压缩成功回调
  success: function (result:IFile) {
    const url = URL.createObjectURL(result)
    console.log('压缩之后图片尺寸大小: ', result.size);
    console.log('mime 类型: ', result.type);
    console.log('实际压缩率: ', ((file.size - result.size) / file.size * 100).toFixed(2) + '%');
  },

  // 发生错误
  error: function (msg:string) {
    console.error(msg);
  }
};

new ImageCompressor(options);

配置项

| Name | Type | Default | Description | | :------------------: | ------------ | --------- | -------------------------------------------------------------------------------- | | file | File Blob | "" | (必传项) 文件 | | quality | number | 0.8 | 自定义配置压缩比 | | mimeType | string | | 输出图片类型 | | convertSize | number | 2048000 | png转jpeg阈值 | | width | number | | 宽度 | | height | number | | 高度 | | maxWidth | number | | 最大宽度 | | maxHeight | number | | 最大高度 | | minWidth | number | | 最小宽度 | | minHeight | number | | 最小高度 | | redressOrientation | boolean | | 是否矫正jpeg方向 | | loose | boolean | true | 是否宽松模式(控制当压缩的图片 size 大于源图片,输出源图片,否则输出压缩后图片) |


otherfunction

array2Tree

import {array2Tree} from "qyh_utils"
const arr = [
  {
    name: '中国',
    id: 1,
    al: 'xx',
    parentId: 0,
  },
  {
    name: '北京',
    al: 'xx',
    id: 2,
    parentId: 1,
  },
  {
    name: '上海',
    al: 'xx',
    id: 3,
    parentId: 2,
  },
  {
    name: '台湾',
    al: 'xx',
    id: 4,
    parentId: 3,
  },
  {
    name: '钓鱼岛',
    id: 5,
    al: 'xx',
    parentId: 4,
  },
]
const tree=array2Tree(arr)

tree2Array

import {tree2Array} from "qyh_utils"
const tree = {
  name: '中国',
  id: 1,
  al: 'xx',
  parentId: 0,
  children: [
    {
      name: '北京',
      al: 'xx',
      id: 2,
      parentId: 1,
      children: [
        {
          name: '上海',
          al: 'xx',
          id: 3,
          parentId: 2,
          children: [
            {
              name: '台湾',
              al: 'xx',
              id: 4,
              parentId: 3,
              children: [
                {
                  name: '钓鱼岛',
                  id: 5,
                  al: 'xx',
                  parentId: 4,
                },
              ],
            },
          ],
        },
      ],
    },
  ],
}
const array=array2Tree(tree)

arrMapObj

import {arrMapObj} from "qyh_utils"
const arr=[{ id: '1', name: 'zs' }, { id: '2', name: 'ls' }]
const obj= arrMapObj(arr,"id")
//  {
//     1: { id: '1', name: 'zs' },
//     2: { id: '2', name: 'ls' },
//  }

deepClone

import {deepClone} from "qyh_utils"
  let info = { item: 1 };
  let obj: Record<string, any> = {
    key1: info,
    key2: info,
    list: [1, 2]
  };

  // 循环引用深拷贝示例
  obj.key3 = obj;
  let cloneObj = deepClone(obj);
  console.log("obj", obj);
  console.log("cloneObj", cloneObj);

observerImg

import {observerImg} from "qyh_utils"
// 图片懒加载 IntersectionObserver
  observerImg()

control

import {control} from "qyh_utils"
// 控制最大并发
   function task1() {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve("task1");
        console.log("task1")
      })
    });
  }
  function task2() {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve("task2");
        console.log("task2")
      }, 1000);
    });
  }
  function task3() {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve("task3");
        console.log("task3")
      }, 20);
    });
  }
  function task4() {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve("task4");
        console.log("task4")
      }, 500);
    });
  }
  function task5() {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve("task5");
        console.log("task5")
      }, 2000);
    });
  }
  const tasks = [task1, task2, task3, task4, task5];
  control(tasks, 2)