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 🙏

© 2024 – Pkg Stats / Ryan Hefner

throttle-listeners

v1.2.0

Published

---

Downloads

2

Readme

throttle-listeners


说明

throttleListeners可以将多个监听器组合并监听一个新的组合值,同时可以对这个值做节流防抖操作,throttleListeners可以保证节流后的state前后两次不相同,避免不需要的state更新。

throttleListeners会在调用时执行一次stateUpdate,参数是listeners里传入的初始值。

参数

type Listener<T> = {
    getDefaultValue: () => T, // 得到监听默认值
    addListener: (callback: (v: T) => void) => void, // 监听值变化
    removeListener: (callback: (v: T) => void) => void, // 取消监听
}
// 参数
listeners: Listener<any>[], // 监听器
getState: (...params) => T, // 将监听值组合成新的值(state)
stateUpdate: (state: T) => void, // state变化需要执行的操作
throttle: (stateUpdate: (state: T) => void) => (state: T) => void = (callback) => callback
// 对state的节流函数

返回值

removeListeners = throttleListeners(...)

执行removeListeners可以调用传递的所有removeListener解除监听

举例:

// 自动检测当前在哪块区域
throttleListeners(
    [
        {
            getDefaultValue: () => window.scrollY, 
            addListener: (callback) => eventEmitter.on('scroll', callback), 
            removeListener: (callback) => eventEmitter.removeListener('scroll', callback)
        },
        {
            getDefaultValue: () => ({x: window.innerWidth, y: window.innerHeight}), 
            addListener: (callback) => eventEmitter.on('resize', callback), 
            removeListener: (callback) => eventEmitter.removeListener('resize', callback)
        },
    ],
    (scrollY, {y: windowHeight}) => {
        let descriptionRect = containers.description.getBoundingClientRect()
        let projectsRect = containers.projects.getBoundingClientRect()
        let professorsRect = containers.professors.getBoundingClientRect()
        let studentsRect = containers.students.getBoundingClientRect()
        let contactRect = containers.contact.getBoundingClientRect()
        if (windowHeight / 2 >= descriptionRect.top && windowHeight / 2 < descriptionRect.top + descriptionRect.height) {
            return 'description'
        } else if (windowHeight / 2 >= projectsRect.top && windowHeight / 2 < projectsRect.top + projectsRect.height) {
            return 'projects'
        } else if (windowHeight / 2 >= professorsRect.top && windowHeight / 2 < professorsRect.top + professorsRect.height) {
            return 'professors'
        } else if (windowHeight / 2 >= studentsRect.top && contactRect.top + contactRect.height * 2 / 3 > windowHeight) {
            return 'students'
        } else {
            return 'contact'
        }
    },
    (name) => {
        setTimeout(() => {
            for (let _name in navItems) {
                if (_name === name) {
                    navItems[_name].forEach(ele => {
                        ele.classList.add('active')
                    })
                } else {
                    navItems[_name].forEach(ele => {
                        ele.classList.remove('active')
                    })
                }
            }
        }, 0)
    },
    callback => debounce(200, false, callback)
)

这个函数实现的功能是:让导航栏中的栏目状态随着屏幕中间的内容块变化而变化。

监听scroll滚动变化和屏幕resize变化,这里的getState虽然没用到scrollY,但是getState里面的container rect位置大小都是scrollY的因变量,所以监听scroll变化还是非常必要的,getState的返回的是当前屏幕中心的内容块;

对新的state使用debounce(throttle-debounce)防抖,参考 节流防抖 里的Debounce At End,使用这个在目前看来是最优解;(那种开始变化立即触发一次,结束变化再触发一次,已证明无用,它其实就是在这个的基础上加了一次开始变化立即触发一次,因为如果是连续变化,开始变化触发的那一次状态就没有必要,因为它还在快速的变化,如果不是连续变化,即变化一次,那立即触发和延时200ms区别也不大,因为你既然设置200ms,就应该能接受连续变化完最后响应速度是200ms,同样的单次变化响应速度也应该能接受)

节流之后的state更新会触发stateUpdate函数,从而更新导航栏中的栏目状态。