Code Monkey home page Code Monkey logo

single-promises's Introduction

single-promises

npm npm github github stars

生成一个单例模式的promise 调用函数。

简体中文 | English

使用

npm

npm install single-promises -S

import

import {singlePromise, version} from 'single-promises'

require

const {singlePromise, version} = require('single-promises')

CDN

jsDelivr CDN

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/single-promises.iife.js"></script>

unpkg CDN

<script src="https://unpkg.com/[email protected]/dist/single-promises.iife.js"></script>
<script>
    const { singlePromise, version } = singlePromises
</script>

Example

test

import { singlePromise } from 'single-promises'
const getTime = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(Date.now())
    }, 1000)
  })
}

const singleGetTime = singlePromise(getTime)

for (let i = 0; i < 5; i++) {
  singleGetTime().then(res => {
    console.log('res', res)
  })
}
// res 1694058404950
// res 1694058404950
// res 1694058404950
// res 1694058404950
// res 1694058404950
// 输出5遍结果,但只获取了一次当前时间

access_token 无痛刷新

实际的实现比这个更加复杂,这里只做关键代码的示例。

import axios from 'axios'
import { singlePromise } from 'single-promises'
import Cookies from 'js-cookie'

const http = axios.create({})

const getAccessToken = (refreshToken) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('新的access token:' + Date.now())
    }, 1500)
  })
}

const singleGetAccessToken = singlePromise(getAccessToken)

http.interceptors.request.use(async config => {
  const token = Cookies.get('access_token')
  if (!token) {
    const refreshToken = Cookies.get('refresh_token')
    const res = await singleGetAccessToken(refreshToken)
    Cookies.set('access_token', res)
  }
  return config
})

多组件api

多个组件同时获取用户信息,使用singlePromise 包装,只需要调用一次。

// api.js
// 多次调用,在api 请求未响应前,只会调用一次api请求,请求响应后会把api 响应结果响应给对应的调用。调用结束后 1000 ms 内,再次调用会直接返回上次调用的结果,不会再次调用api 请求。调用结束后 1000 ms 后,再次调用会直接调用api请求
const getUserInfo = singlePromise((params) => axios.get('api/userInfo', {params}), {cache: 1000})
<script>
/** Header.vue **/
{
    created () {
    	getUserInfo()
    }
}
</script>
<script>
/** Footer.vue **/
{
    created () {
    	getUserInfo()
    }
}
</script>
<script>
/** Article.vue **/
{
    created () {
    	getUserInfo()
    }
}
</script>
<template>
<div>
    <Header/>
	<Article/>
	<Footer/>
</div>

</template>
<script>
/** Layout.vue **/
{
    created () {
    	getUserInfo()
    }
}
</script>

多个组件同时调用,只会调用一次api 请求

API

singlePromise

第一个参数接收一个函数,第二个参数接收一个配置项对象。返回一个函数。

singlePromise(fn[, options])

Return: Function

fn

Type: Function

要调用的函数。当执行返回的函数时,this上下文和所有参数将按原样传递给 fn。fn 函数可以返回promise,或其他,因为在singlePromise 函数内部,fn函数将被Promise.resolve 函数包裹。

options

Type: Object

Default: {cache: 0}

可选。配置项

options.cache

Type: Number

Default: 0

fn函数返回结果后的缓存时间,单位ms。在缓存时间内,下次调用将直接返回缓存的结果。默认0 不缓存。缓存时间从fn 函数返回fulfilled状态开始算起,如果fn函数返回rejected状态则不缓存。

返回函数

const handle = singlePromise(() => Promise.resolve('response'), {cache: 1500})

Return: Promise

handle 函数调用返回一个promise, 这个promise的 fulfilled/ rejected 状态取决于 fn函数返回的promise 的状态。当执行handle 函数时,this上下文和所有参数将按原样传递给 fn

handle.clear

Type: Function

清除缓存结果函数。调用将清除上次的缓存结果。

handle.update

Type: Function

handle.update(options)

更新options函数。handle.update({cache: 1000}),调用后将更新handle 的配置。

version

当前包的版本号

常见问题

如果在vue 使用

注意:需要在 data 配置项 调用创建,不然会丢失 handle.clearhandle.update 方法

<script>
// vue2
import { singlePromise } from 'single-promises'
{
	data () {
		return {
            	singleGetUserInfo: singlePromise((params) => axios.get('api/userInfo', {params}), {cache: 1000})
			}
	}
}
</script>

throttledebounce 的区别

throttle/debounce 都取决于指定时间内做什么事,而singlePromise 取决于 fn函数返回的promise pending 状态时做什么事

single-promises's People

Contributors

lei-mu avatar

Stargazers

Seeker avatar  avatar 可乐 avatar  avatar Shan Yinlong avatar  avatar millerye1995 avatar  avatar roastwind avatar Golden avatar

Watchers

 avatar

single-promises's Issues

需要index.d.ts 实现

源码:https://github.com/lei-mu/single-promises/blob/master/lib/index.js

import {version} from '../package.json'



/**
 * 用于包装一个函数并返回一个新函数,使其调用这个新函数只有一个promise在执行,后续的调用都会返回这个promise
 * @param fn {function(...[*]): (Promise<Awaited<*>>)} - 需要包装的函数
 * @param opt {object} - 配置项
 * @param opt.cache {number} [opt.cache = 0] - 缓存时间,单位毫秒,如果大于0,则会缓存结果,下次调用如何结果仍在有效缓存时间内,则会直接返回缓存的结果。默认0,不缓存
 * @return {(function(...[*]): (Promise<Awaited<*>>))|*}
 */
  function singlePromise(fn, opt = {}) {
    const defaultOpt = {
    cache: 0
    }
    let promise
    let cacheMill = -1
    let cacheRes

  opt = Object.assign({}, defaultOpt, opt)

  function handle(...args) {
    let self = this
    let {cache} = opt

    if (cache && cacheMill > 0) {
      if (Date.now() - cacheMill < cache) {
        return Promise.resolve(cacheRes)
      } else {
        cacheMill = -1
        cacheRes = null
      }
    }
    if (promise) {
      return promise
    } else {
      promise = Promise.resolve(fn.apply(self, args))
    }
    return promise.then((res) => {
      if (cache) {
        cacheMill = Date.now()
        cacheRes = res
      }
      promise = null
      return res
    }).catch((err) => {
      promise = null
      return Promise.reject(err)
    })
  }

  handle.clear = function () {
    cacheMill = -1
    cacheRes = null

  }
  handle.update = function (newOpt = {}) {
    opt = Object.assign({}, opt, newOpt)
  }

  return handle

}

export {
  singlePromise,
  version
}

上面是我js 工具库的实现。
我需要index.d.ts 实现。

使用示例

const getTime = (t) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(Date.now() * t)
    }, 1000)
  })
}
const singleOptions = {
  cache: 0
}


const singleGetTime = singlePromise(getTime, singleOptions)

for (let i = 0; i < 5; i++) {
  // 希望调用 时能有参数提示,参数同getTime
  singleGetTime(3).then((res) => {
    console.log('res', res)
  })
}
// 希望能有 clear 方法提示
singleGetTime.clear()
const newSingleOptions = {
  cache: 1
}
// 希望能有 update 方法提示、参数提示
singleGetTime.update(newSingleOptions)


// fn 支持同步函数。
const getTime2 = (str) => {
  return Date.now() + str
}

// fn 可以是同步函数,但singlePromise 函数返回的函数,调用时永远返回promise
const singleGetTime2 = singlePromise(getTime2)
  1. singleOptions 是可选的。singleOptions.cache 是number,也是可选的

  2. singlePromise 的第一个参数 fn 必传,函数类型。

    fn 可以是同步函数,也可以是promise

  3. singlePromise 的第二个参数是 singleOptions ,非必填。

  4. singlePromise 调用时,返回一个函数 handle

    handle 接收的参数会传递给 fn。

    handle 调用 返回值是一个Promise

    Promise(别名:p1) 的返回值取决于 fn。fn 的返回值会被 Promise.resolve 包裹。响应表现如Promise.resolve

     如果fn 是一个同步函数,那 fn 的返回值 会在 Promise 结果 体现
    
     如果fn 返回一个Promise(别名:p2),那p1 的相应状态取决于 p2 的相应状态。
    
    
    
    handle.update 一个参数,非必传。参数类型为 singleOptions。为一个函数
    
    handle.clear 无参数。为一个函数
    调用handle 时希望有fn 的参数提示,和返回值提示
    

5.singleGetTime 作为函数调用时,参数和 返回值同 fn,不同的是fn 不一定返回promise,但 singleGetTime 作为函数调用时,返回值一定是Promise,值类型同 fn 的返回值类型

以下是我的一些尝试,但是似乎达不到想要的效果

declare module 'single-promises' {
    export interface SingleOptions {
        cache?: number;
    }

    type FunctionType<T> = (...args: any[]) => T extends Promise<infer U> ? Promise<U> : Promise<T>;

    export interface SinglePromiseHandle<T> {
        (...args: Parameters<FunctionType<T>>): ReturnType<FunctionType<T>>;
        clear(): void;
        update(newOpt?: SingleOptions): void;
    }

    export function singlePromise<T>(fn: FunctionType<T>, opt?: SingleOptions): SinglePromiseHandle<T>;

    export const version: string;
}

如果需要提交pr, 请合并至 ts 分支

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.