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

take-latest-generator-co

v0.2.2

Published

利用generator解决竞态情况,在少量修改原代码的情况下,就能解决

Downloads

2

Readme

take-latest-generator-co

Description

利用generator解决竞态情况,在少量修改原代码的情况下,就能解决竞态问题。 不需要引入额外的框架。也不需要外部的变量来控制。整体相对于以前用 async/await 方式来写的代码差别很小。

解决方案原理:可查看文章 详细流程说明

===================

安装

npm install take-latest-generator-co

在 vue 中使用:

import { watchCallbackGeneratorWarp, takeLatestWarp } from 'take-latest-generator-co/dist/vue'
// 如果想更彻底的取消请求, 节省用户流量。 可以使用 fetchWithCancel,代替 fetch。
import { fetchWithCancel } from 'take-latest-generator-co/dist/fetchWithCancel'


// demo, 网络请求业务函数,改成 generator 函数
function * fetchAndSetData(val) {
  const args = queryList.value[val]
  try {
    firstData.value = yield* fetchDelayTime({ data: args.data + 'f', time: args.time / 2 })
    let res = yield* fetchDelayTime(args);
    secData.value = res
    return res
  } catch (error) {
    console.error('fetchAndSetData error', error)
  }
}

// demo, 封装的网络请求函数
function * fetchDelayTime({ data, time }) {
  let res = yield fetch(`/api/delayTime?data=${data}&time=${time * 1000}`, {
    cache: "no-store",
  })
  res = yield res.json()
  res = res.data
  return res
}

// 一种场景在 watch 时,进行竞态处理
watch(
  () => currentIndex.value,
  // generator 业务函数,进行包装。 处理后的函数,会自动进行竞态处理。
  watchCallbackGeneratorWarp(fetchAndSetData)
);

function changeIndex() {
  currentIndex.value = 1
}

// 另一种场景,点击事件时,进行竞态处理。 takeLatestWarp 包装后的generator函数,会自动进行竞态处理。
const clickFetch = takeLatestWarp(fetchAndSetData)
<button @click="clickFetch()" >
  点击获取数据
</button>
<button @click="changeIndex()" >
  点击触发watch
</button>

在 react 中使用:

// 如果想更彻底的取消请求, 节省用户流量。 可以使用 fetchWithCancel,代替 fetch。
import { fetchWithCancel } from 'take-latest-generator-co/dist/fetchWithCancel'
import { useCallBackTakeLatest, useEffectTakeLatest, turnToAsyncWarp } from 'take-latest-generator-co/dist/react'

const [currentIndex, setCurrentIndex] = useState()

// demo, 封装的网络请求函数
function * fetchDelayTime({ data, time }) {
  let res = yield fetch(`/api/delayTime?data=${data}&time=${time * 1000}`, {
    cache: "no-store",
  })
  res = yield res.json()
  res = res.data
  return res
}

// demo, 网络请求业务函数,改成 generator 函数
function * effectFetchSetData() {
  if (currentIndex === undefined) return
  const args = queryList[currentIndex]
  const firstD = yield* fetchDelayTime({ data: args.data + 'f', time: args.time / 2 })
  setFirstData(firstD)
  let res = yield* fetchDelayTime(args);
  setSecData(res)
  return res
}

// 一种场景在 useEffect 时, 监听数据变化, 进行竞态处理。 利用 useEffectTakeLatest 这个 hook,进行包装。 处理后的函数,会自动进行竞态处理。 useEffectTakeLatest 是 useEffect 的竞态处理版本。
useEffectTakeLatest(effectFetchSetData, [currentIndex])

// 另一种场景,点击事件时,进行竞态处理。 useCallBackTakeLatest 包装后的 generator 函数,会自动进行竞态处理。 useCallBackTakeLatest 是 useCallback 的竞态处理版本。
const clickFetch = useCallBackTakeLatest(fetchAndSetData, [])

return (
  <div>
    <button onClick={() => clickFetch(index)}>点击处理竞态</button>
    <button onClick={() => setCurrentIndex(index)}>在useEffect中,进行竞态处理</button>
  </div>
)

本npm包的所有导出函数

core.d.ts
export declare interface PromiseWithCancel<T> extends Promise<T> {
    abortThisPromise?(reason?: EAboutReason | string): void;
    __ABORT_REASON__?: string;
}
/** 根据 GeneratorFunction 推断 迭代器最后的return值
 *  @template Gf - GeneratorFunction
 * */
export declare type GeneratorFunctionReturn<Gf extends GeneratorFunction> = ReturnType<Gf> extends Generator<any, infer R, any> ? R : never;
export declare enum EAboutReason {
    CANCEL = "cancel"
}
/**
 * 给 Promise 添加带取消函数的一些方法,包括  'all', 'allSettled', 'any', 'race'。
 * 默认会增加 'allWithCancel', 'allSettledWithCancel', 'anyWithCancel', 'raceWithCancel' 四个方法。
 * 增加的方法后缀默认为 'WithCancel',可以通过参数修改。
 * @param {PromiseConstructor} originPromise - Promise 原始对象。
 * @param {string} [suffix='WithCancel'] - The suffix to be added to the cancellation methods.
 */
export declare function appendPromiseCancelMethods(originPromise: PromiseConstructor, suffix?: string): void;
/**
 * Generator 的核心控制函数,控制 Generator 的执行和取消逻辑。
 *
 * @param {Function} fetchGenerator - Generator函数
 * @param {...any} args - fetchGenerator 函数的参数
 * @returns {Object} - 一个对象,包括 doFetch 和 cancel 两个方法,doFetch 用于执行 Generator 函数,cancel 用于取消执行。
 */
export declare function generatorCtrl<T extends GeneratorFunction>(fetchGenerator: T, args?: Parameters<T>): {
    doFetch: () => Promise<GeneratorFunctionReturn<T> | any>;
    cancel: () => void;
};
/**
 * 讲 Generator 函数包装,并返回一个包装过的 async 函数。该函数在开始新执行之前取消任何先前的未执行完成的流程。
 * 保证最后一次执行。
 * @param {Function} fetchGenerator - 需要包装的 Generator 函数
 * @returns {Function} - 返回对应的 async 函数
 */
export declare function takeLatestWarp<T extends GeneratorFunction>(fetchGenerator: T): (...args: Parameters<T>) => Promise<GeneratorFunctionReturn<T> | any>;
/**
 * 一个包装函数,用于 将 Generator 转换成 async 函数,自动执行,无法执行取消操作,像正常的async一样使用。
 * @param {Function} fetchGenerator - 需要包装的 Generator 函数
 * @returns {Function} - 返回对应的 async 函数
 */
export declare function turnToAsyncWarp<T extends GeneratorFunction>(fetchGenerator: T): (...args: Parameters<T>) => Promise<GeneratorFunctionReturn<T>>;
/**
 * 定时器,返回一个 Promise,在指定的时间后 resolve,可以取消
 *
 * @param {number} ms - 指定的时间,单位毫秒
 * @returns {Promise} - 返回的 Promise 实例上增加 abortThisPromise 方法, 可以取消这个 Promise
 */
export declare function delayWithCancel(ms?: number): PromiseWithCancel<any>;
react.d.ts
import { type GeneratorFunctionReturn } from './core';
export * from './core';
type DependencyList = readonly unknown[];
/**
 * useCallBack 的 takeLatest 版本,在依赖数组未发生变化的情况下,新的执行会自动取消上一次的未完成的执行。
 * 所以为了能保证每次都能打断,deps 最好是空数组。
 *
 * @template T - The type of the generator function.
 * @param fetchGenerator - 需要包装的 generator 函数。
 * @param deps - 依赖数组
 * @returns 返回一个 async 函数,该函数在开始新执行之前取消任何先前的未执行完成的流程。
 */
export declare function useCallBackTakeLatest<T extends GeneratorFunction>(fetchGenerator: T, deps: DependencyList): (...args: Parameters<T>) => Promise<GeneratorFunctionReturn<T> | any>;
/**
 * useEffect 的 takeLatest 版本,新的执行会自动取消上一次的未完成的执行。
 *
 * @param  fetchGenerator - Generator 函数。
 * @param  deps - useEffect 的依赖数组
 */
export declare function useEffectTakeLatest<T extends GeneratorFunction>(fetchGenerator: T, deps: DependencyList): void;
vue.d.ts
export * from './core';
/**
 * 将 Generator 函数包装,该函数可以作为 `watch` 的第二个参数回调函数。
 * 在开始新执行之前取消任何先前的未执行完成的流程。
 *
 * @template T - The type of the generator function.
 * @param fetchGenerator - 需要包装的 generator 函数。
 * @returns 返回一个函数,作为 `watch` 的回调函数。
 */
export declare function watchCallbackGeneratorWarp<T extends GeneratorFunction>(fetchGenerator: T): (val: unknown, oldVal: unknown, onCleanup: OnCleanup) => void;
/**
 * 将 Generator 函数包装,该函数可以作为 `watchEffect` 的回调函数。
 * 在开始新执行之前取消任何先前的未执行完成的流程。
 *
 * @template T - The type of the generator function.
 * @param fetchGenerator - 需要包装的 generator 函数。
 * @returns 返回一个函数,作为 `watchEffect` 的回调函数。
 */
export declare function watchEffectCallbackGeneratorWarp<T extends GeneratorFunction>(fetchGenerator: T): (onCleanup: OnCleanup) => void;

axiosWarp.d.ts

/**
 * 创建带有取消请求功能的 Axios 实例
 * @param {object} originAxios - 原始的 Axios 实例
 * @param {object} config - Axios 实例的配置
 * @returns {object} - 带有取消请求功能的 Axios 实例
 */
export declare function createAxiosWithCancelRequest(originAxios: AxiosStatic, config: CreateAxiosDefaults): AxiosInstance;

fetchWithCancel.d.ts

import type { PromiseWithCancel } from './core';
declare type IFetch = typeof fetch;
/**
 * 包含取消方法的 fetch 函数。返回的 Promise 实例上增加 abortThisPromise 方法, 可以取消这个 Promise
 * @param  args - fetch 函数的参数
 * @returns {Promise<Response>} - 返回的 Promise 实例上增加 abortThisPromise 方法, 可以取消这个 Promise
 */
export declare function fetchWithCancel(...args: Parameters<IFetch>): PromiseWithCancel<Response>;
export {};