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

rexos

v2.0.3

Published

an ajax library

Downloads

10

Readme

rexos

全方位拥抱Typescript,完全重构了@tencent/db库,并提供了重量级别的新功能.

install

npm

npm install -S rexos

从其他框架迁移

@tencent/db

  • redux/db 默认不发送cookie,你需要主动设置with-credentials

    如果从@tencent/db迁移,应该初始化DB

    DB.defaults['with-credentials'] = true
  • api middleware rexos已经提供了兼容api middleware action的中间件.

    不过在rexos里,call api必须引用自rexos/middleware/api,因为它是一个Symbol,而非一个字符串.

  • extension

    rexos本身没有实现任何扩展.@tencent/db原有的扩展应该使用rexos提供的插件机制进行添加.

  • err/succ回调

    rexos本身已经实现了beforeafter回调,保留的errsucc仅为了支持老式的中间件,如果错误处理需求,应该配置全局after拦截器,并在其中进行错误判断.

axios

rexos的接口几乎与axios一致,参照文档开发即可。

功能:

拦截器:

  • 可拔插的全局拦截器及单次请求拦截器
  • 可在请求中精确静止某个拦截器,而不用axios.create重新创建请求实例
  • 易用的插件机制,可配置多种hooks
  • 支持链式修改config,链式返回data

代理

rexos内置了跨域代理功能,因为node的一些api无法运行于浏览器上,所以需要配合webpackPlugin或者主动开启server

  • 主动开启:

    const startServer = require('rexos/lib/proxy').startServer
    startServer()
  • 使用WebpackPlugin开启:

    const plugin = require('rexos/lib/proxy').rexosProxyPlugin
    plugins.push(new plugin())

性能:

rexos池化了需要重复创建的请求实例类DB和请求发送类Sender,并且在钩子里面精确掌控了释放的时机,对用户完全透明.

当然,减少gc的副作用是丢失了对异步钩子的支持.不过,如果必要的话,你可以调用persist来阻止自动入池,并且手动release达到可控复用.

强大的功能:

  • cancelToken:

    它不基于Cancelable Promises提案,所以你可以随意的使用它而不考虑兼容性.具体的使用方案你可以查看axios,rexos完全兼容axios cancelToken接口.

  • fetch:

    是的,rexos现在默认采用fetch api来获取数据.当然,在fetch不被支持的环境下,它还是会回退到ajax.

  • 缓存:

    rexos提供了强大的缓存能力,它的策略来自于PWA workbox:

    • cache-first
    • cache-only
    • network-first
    • network-only
    • stale-while-revalidated

    不过,这些能力需要配套的中间件提供支持(已经附赠),rexos本身并不提供.

  • preload

    有了rexos,顺带实现preload是非常简单的事情.值得一提的是,preload会优先利用link原生缓存图片类数据.

API

useFetch

useFetch(string | DbOptions)

import { useFetch } from 'rexos'
useFetch('www.baidu.com').then(data => {
    console.log(data)
})

默认情况下,useFetch接收一个DbOptions对象

// DbOptions
type someProperty = {
    url:string,
    successStatusRange ?:[] | number,
    complete ?: () => void,
    fail ?: () => void,
    data ?:object,
    type ?:RequestType,
    query ?: object,
    'Content-Type' ?: string,
    'with-credentials' ?: boolean,
    headers ?:HeadersType,
    cache ?: CacheType,
    timeout ?: number,
    // 是否开启请求耗时计算
    perf ?: boolean,
    transformData ?: Function,
    cancelToken ?: (acceptCancel:unknown) => void,
    updateCache ?: IUpdateCache,
    // 本次请求关闭插件
    bannerPlugins ?: string[],
    before:Before[],
    after:After[],
    rawUrl ?: boolean,
    json ?: boolean
}

当然,如果你只需要使用简单的Get请求,那么也可以使用

useFetch('www.baidu.com')
// ==
useFetch({
    url: 'www.baidu.com',
    method: 'GET'
})

基础使用

@tencent/db一致,rexos提供了取数中间件,你可以以一个模块的形式维护数据

getDataAction() {
    return {
        [CALL_API]: {
            url: 'ke.qq.com/data/some...'
        }
    }
}

Content-Type

默认的,如果你为data传入一个对象,且type不为GET,则rexos将以application/json的形式发送请求。

如果你需要以application/x-www-form-urlencoded的形式传入,指定参数form: true

transformData

rexos提供了数据转换的功能,你可以通过它修改返回的数据

不过,如果你需要以一定的规范修改返回的数据,或者进行复杂的转换,建议使用interceptor

getDataAction() {
    return {
        [CALL_API]: {
            url: 'ke.qq.com/data/some...',
            transformData(data) {
                return {
                    ...data,
                    ...extra
                }
            }
        }
    }
}

interceptor

作用范围:

  • global interceptor

    每次请求都会执行的全局拦截器,一处配置,处处生效

  • action interceptor

    仅在单次请求里生效

类型:

  • before(request):

    before(config => config,[name:any])

    • 每个before拦截器都会在发送请求前调用,它接收一个配置,并返回一个配置.
    // usage:
    before = (config) => {
        // do something
        return {
            ...config,
            extra:...
        }
    }

    需要注意的是,before拦截器并不进行shallow merge,你需要返回全部配置

  • after(response):

    after(data => data,[name:any])

    每个after拦截器都会在得到数据并检查结果后调用,它接收一个已经由可选配置transformData转换好的数据,并返回一个新的数据.

    需要注意的是,after拦截器并不是最早接触到返回数据的函数,在它之前至少会经过checkStatus这个阶段.如果返回的status不是可接受的,那么不会调用after拦截器.

你可以在拦截器里访问Sender操作类,但这要求你不要使用箭头函数

global

对于任何全局拦截器,都必须要提供一个name进行注册

DB.interceptors.before.use(config => config,'default')
action

相反,对于action级别的拦截器,不用进行任何注册,它只作用于当次请求

getDataAction() {
    return {
        [CALL_API]: {
            before:[config => config]
        }
    }
}
close globalInterceptor

axios里,我们有一个很大的困惑就是,配置了全局拦截器后没办法在某次请求里消除.只有通过axios.create创建的全新的实例来清除拦截器.

问题是,我们可能只需要清除某一个拦截器,比如某次不用上报的请求,我们在发送前需要清理掉上报拦截器,但保留其余的拦截器,重新创建实例会新增很多不必要的工作.

rexos里面,禁用掉某次请求的某个全局拦截器非常简单

getDataAction() {
    return {
        [CALL_API]: {
            bannerPlugins:['before-report','after-report']
        }
    }
}

这需要使用者命名的规范性,比如以before-开头

内置的拦截器

rexos还有两个内置的拦截器:

  • succ
  • err

⚠️:这两个拦截器仅用来支持老式的中间件,请不要主动使用他们.

DB.addExtensions('succ',name,handler)

cancelToken

上面已经提到,cancelToken并不依赖于Proposal Cancelable Promises.它精确的控制了请求是否应该被关闭. 不过,自定义的cancelToken接口必须满足(cancel) => acceptedCancel = cancel这样的形式.

未来会考虑用工厂函数的形式构造,但都需要使用者适配接口的规范.

let cancel
let cancelToken = (_cancel) => cancel = _cancel

getDataAction({cancelToken}) {
    return {
        [CALL_API]: {
            cancelToken
        }
    }
}

setTimeout(() => cancel(),1000)

注意,即使关闭了某个请求,也会返回一个type = failaction,但它不会对仓库造成任何影响.

缓存

依赖于localStorage,rexos提供了一些缓存策略,具体的方案你可以查阅Google PWA Workbox.下面只列出几个常用的策略

  • cache-first(default)

    在这种情况下,rexos会优先寻找缓存,不论缓存是否存在,都会向目标请求数据,并在成功后更新缓存.

  • network-first

    在这种情况下,rexos会优先请求数据,但在首次失败后,rexos将不会再次请求,而是返回缓存.

  • network-only

    在这种情况下,rexos会优先请求数据,但在首次失败后,api middleware会直接返回一个type:failaction

getDataAction() {
    return {
        [CALL_API]: {
            useLocal: {
                key: ...,
                strategy: 'cache-first'
            }
        }
    }
}

配置

rexos提供全局配置扩展,一处修改,处处生效.

DB.defaults.baseUrl = ''
...

请求头

ContentType
  • general:

    为兼容@tencent/db,POST默认的Content-Typex-www-form-urlencoded,不过你可以手动指定为application/json

    默认情况下,你不需要手动转换data,只需要指明Content-Type即可

    getDataAction() {
        return {
            [CALL_API]: {
                type:'POST',
                headers: {
                    data: {
                        name:'lyl',
                        age:20
                    }
                }
            }
        }
    }

    手动指定为json

    getDataAction() {
        return {
            [CALL_API]: {
                headers: {
                    'Content-Type': 'application/json',
                    data: {
                        name:'lyl,
                        age:20
                    }
                }
            }
        }
    }
  • form-data:

    如果需要上传form-data形式的数据,你依然需要设置multipart:form-data.不过不要担心,rexos并不会上传这个header,它只是作为内部的一个标识而已.

    甚至,你可以直接以一个构建好的FormData作为data,这样就不需要指定header了.

    getDataAction() {
        return {
            [CALL_API]: {
                type:'POST',
                headers: {
                    'Content-Type': 'multipart/form-data',
                }
            }
        }
    }

cdn select

你可以提供多个cdn,rexos会选择最快的一个返回,并在后面的请求中自动切换到该cdn(这个过程用户不会感知)

使用该功能,你需要在action里:

  • 注册该cdn组的name
  • 配置isCdnSelect参数为true
  • 修改urlurls
getDataAction() {
    return {
        [CALL_API]: {
            name: 'dataget'
            isCdnSelect: true,
            urls: ['dataget/cdn1','dataget/cdn2','dataget/cdn3']
        }
    }
}

需要注意的是,rexos只会在session生命周期内保存最快cdn.

可能会遇到的问题

上面已经提到过,rexos自动池化了某些关键类,这导致了一些response拦截器里无法异步访问数据

DB.interceptors.after.use(function(){
    setTimeout(_ => {
        console.log(this.data) // undefined or dirty data
    },0)
},'async')

这是因为Sender类在同步执行完所有response拦截器后就会自动回收入池,如果需要的话,你需要主动调用persist方法阻止这种行为.

DB.interceptors.after.use(function(){
    this.persist()
    setTimeout(_ => {
        console.log(this.data) // normal
    },0)
    this.release()
},'async')

但请注意的是,在使用完后,需要手动调用release把它释放,否则它将不能得到复用.

至于释放的时机,你可以合理的分配自己的拦截器.但为了规避一些不必要的错误,尽量不要使用在拦截器里异步访问数据.