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

focus-flow

v1.2.14

Published

让代码变成一条流

Downloads

42

Readme

focus-flow

gitHub Version

让代码变成一条流

API Documentation

Features

  • 将后端中间件方式移植到前端,通过维护ctx上下文来处理业务逻辑,降低函数间的耦合
  • 实现节流,队列,池等概念
  • 支持async/await

Installing

// npm
npm i -S focus-flow
import FocusFlow from 'focus-flow'
// script
<script src="https://unpkg.com/focus-flow/dist/focusFlow.js"></script>

Chestnut

曾几何时,你有没有被反复无常的需求弄得心烦意乱。

举个例子:一个商城代理模块,当代理要发展下线的时候,要通过二维码让新用户扫码,才可以绑定用户。

function isRegister(){
  if(is){
    getUserInfo()
  } else {
    register()
  }
}
agent(id){
  //是否有代理id
  if(id) 
}
register(){
  agent()
  getUserInfo()
}

好不容易把业务写好了,过了数天,产品:“小马啊,发展下线这个逻辑改成-----非代理用户,第一次扫代理二维码的时候就成为代理的下线”。

这时候又得屁颠颠的从register函数上找到agent注释掉,放到合适的地方。

又过了数天,产品走过来一边帮按摩一边说:”小马啊,发展下线这个逻辑改成......“(产品猝

遇到类似这样的变更,都得到之前的业务逻辑上来找这函数,如果时间一长,或者代码一庞大,改起来就会变得缩手缩脚,特别是别人来接手,函数调来调去,看起来不知道那是头那是尾。

如果把函数按照一个从上而下的流来引用,每个函数封装成一个中间件,通过维护上下文ctx来降低函数间的耦合度,是不是会更好?

然后搞搞,终于把业务代码变成了下面这样

//每个回调函数会接受到3个参数,分别是ctx、next、close
const master = new FF()
  .use(isRegister) //是否注册
  .use(register) //注册
  .use(getUserInfo) //获取用户
  .use(agent) //成为下线
//启动的时候
master.start()

可读性变得更强,并且修改变动每条管道(use的回调函数之为管道)的时候,我们只需要关注ctx即可。

当然,如果你不想按步就班,你大可next(FocusFlow|Number|String|Boolean)来进行定点执行或跨管道

Options

// 以下是默认配置
new FF({
  threadMax: 1, //最大线程数
  switch: true, //是否开放线程池
  life: -1, //清理线程的周期,毫秒单位, -1为永生
  hand: null, //函数this指向
  queue: false, // 是否开启队列
  queueMax: 10 // 队列上限
})

threadMax:用来限制threads的上限,当达到上限且其中线程都仍活跃,使用start就不会再创建成功,也就意味着该次的start无法成功执行

switch:threadMax如果是一个容器,那么switch则是这个容器的开关

life:规定线程的寿命,-1为永生,止至到线程执行完毕。每当回调函数使用next时,都会刷新线程的寿命。线程池会根据线程的寿命去清理掉那些过期的线程。

hand:回调函数的全局this指向

queue:线程池满了之后的任务都会储存到队列中,线程池有空闲位置时,按照队列先进先出进入线程池中

queueMax:队列任务的上限

Concept

跨管道

何为跨管道?因为有些情景可能不止一条管道分支,宛如git上的一条条不同的分支,正常流程上线用到master分支,但当你要处理bug的时候,有可能就需要建一个bug_dev分支了。同理,当我们的master管道出现正常流程之外的事情,我们可以在回调函数里面是用next(ff2, [sign]),就像git checkout ff2那样,让一个专门处理非正常流程的分支去处理这些逻辑,这样整个业务都变得侧层级分明。

线程

getList(){
  if(close) return 
  close = true
  //异步逻辑,完成后把close设置成false
}

上拉加载的时候,用节流去限制请求接口次数。不知道你有没有写过类似代码,或者用闭包去实现。如上功能,FF也可以实现。

const ff = new FF()
  .use(getList(ctx, next){
    // 异步逻辑,完成后next
    // 还有一个状况,假设判断后台的所有列表数据已经返回完了,那么再触发这段管道就没有意义了。这时候我们就可以使用ctx.$info.ff.close关闭掉线程池。
  })
ff.start({接口参数})

每当ff使用start(成功使用)的时候,内部就会新建一条线程,该线程会负责该次start的请求。而ff中的threads是专门用来储存这些线程。

队列

线程池溢出的任务都会储存到队列中,而队列中除了任务上限,还有入口和出口。

入口:线程池溢出的任务去向。

  • closeQueue 关闭队列入口
  • openQueue 打开队列入口

出口:线程池空闲后任务进入的方向

  • closeExit 关闭队列出口
  • openExit 打开队列出口

事件

callback(ctx, FocusFlow)

  • onFull:线程池溢满事件
  • onQueueFull:队列溢满事件

explain

基本管道

success,fail:callback(ctx, next, close) end:callback(ctx) error:callback(error, ctx, next, close) success:next()到底的时候就会触发该管道。当然,你也可以next(true)直接执行成功管道

fail:next(false)的时候触发

end:success和fail的下一个next就是end,而error则是触发完自己的回调函数后,会自动触发end

error:捕获错误管道

回调函数接受的参数

ctx:管道传递的上下文,ff.start(参数)的参数会合并到ctx上。

$info:

  • id: 线程的id
  • index:当前管道坐标
  • ff: 创建该线程的FF实例
  • life: 线程的生命周期,-1知道线程执行完成

next:可传递2个参数。

  • 第一个参数param是Number类型时,会跳转到第param条管道并执行(没有符合则相当于next())
  • 第一个参数param是String类型时,会跳转到标记为param的管道并执行(没有符合则相当于next())
  • 第一个参数param是Boolean类型时,会跳转到相应的基本管道并执行
  • 第一个参数param是FocusFlow类型时,会进行跨管道(相当于FocusFlow的实例.start(当前ctx,第二个参数)),第二个参数重复以上行为

close:清理当前执行线程,但线程是还会执行完任务

ff.start

有时候,当我们执行到某一段逻辑时,因为某些原因中断了流程。当我满足了该条件后,又不想重新由头到尾执行该管道分支,那应该怎么办?我想有同学大概能想到,start(ctx,sign)

用小程序举个例子:

const master = new FF()
export default master
  .use(userInfo) // 获取微信用户信息
  .use('code', code) // 获取code
  .use(openid) // 获取openid
  .use('myInfo', myInfo) //获取openid
  .use('register', register) //注册

当有用户没有授权微信用户信息的时候,我们从userInfo跳出,然后用某种方法(个人用发布订阅)触发出授权弹框让他们授权,点击授权后调master.start(用户数据,'code'),直接跳到code管道,然后进行接下来的逻辑。