Skip to content

Instantly share code, notes, and snippets.

@xialvjun

xialvjun/limit.js

Last active Apr 13, 2018
Embed
What would you like to do?
// 返回一个可以任意执行,但内部并发只有 count 的函数
function limit(fn, count) {
let n = 0;
let ps = [];
function work(...args) {
n++;
let rp = fn(...args);
rp.then(_ => {
n--;
let next = ps.shift();// ps[0];
if (next) {
// ps = ps.slice(1);
next.resolve(true);
}
}).catch(e => {
n--;
let next = ps.shift();
if (next) {
next.resolve(true);
}
throw e;
});
return rp;
}
return function(...args) {
fn = fn.bind(this);
if (n === count) {
return (new Promise((resolve, reject) => {
ps.push({resolve, reject});
})).then(_ => work(...args));
}
return work(...args);
}
}
export function parallel_limit(fn, count=1) {
const ps = [];
let working = 0;
return function(...args) {
// 把返回的箭头函数改为普通函数,并且修改 fn 的 this,从而让包装后的函数能被外界操纵 this...
// 当然,如果传进来的 fn 已经是一个 bind this 之后的函数,那就无影响...
// 整体上就是尊重外界传递的 fn 的绑定状态...适合于 @xialvjun/create-react-context 库
fn = fn.bind(this);
return new Promise((resolve, reject) => {
ps.push({ resolve, reject, args });
work();
});
};
function work() {
if (working >= count) {
return;
}
const next = ps.shift();
if (next) {
working++;
fn(...(next.args))
.then(_ => {
working--;
work();
next.resolve(_);
})
.catch(e => {
working--;
work();
next.reject(e);
});
}
}
}
export function args_parallel_limit(fn, count=1) {
const args_fns = [];
return function(...args) {
fn = fn.bind(this);
let args_fn = args_fns.find(args_fn => args_fn[0].length === args.length && args_fn[0].every((arg, i) => arg = args[i]));
if (args_fn) {
return args_fn[1](...args);
}
args_fn = [args, parallel_limit(fn, count)];
args_fns.push(args_fn);
return args_fn[1](...args);
}
}
((function(doc, win) {
var docEle = doc.documentElement,
evt = "onorientationchange" in window ? "orientationchange" : "resize",
fn = function() {
// 414 是设计稿 iPhone 6 Plus 的宽度。。。实际需要的时候,需要把 414 换成真实设计稿的宽度
// docEle.style.fontSize = (100 / 414) + "vw";
var width = docEle.clientWidth;
// 本来 docEle.style.fontSize 只需要 = width/414 就好, width/414 值会很小,而浏览器有最小字体限制,导致该项无用,所以乘以 100
width && (docEle.style.fontSize = (100 * width / 414) + "px");
// 于是以后的所有的长度,都直接使用设计稿里的长度的数字,但是把单位换成 rem,并除以 100。。。不用程序员去换算百分比
};
win.addEventListener(evt, fn, false);
doc.addEventListener("DOMContentLoaded", fn, false);
})(document, window));
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
*::-webkit-scrollbar {
/*
这里不用担心,scrollbar 的宽度不会占用百分比。。。
但是从有 scrollbar 变为无 scrollbar,内容的宽度仍然会发生改变,可能把 scrollbar 变成游离元素会更好
*/
width: 5px;
}
*::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
}
*::-webkit-scrollbar-thumb {
background-color: darkgrey;
outline: 1px solid slategrey;
}
/*
其实要实现跟 mac 原生滚动条一模一样,有三个难点:
1. 样式。。。但这个已经没有了,因为能设置样式了
2. 滚动条不占位置。。。这个我没解决,我想把他脱离文档流,但发现做不到,想设置 margin-left 负数,也没用
3. 滚动条在滚动时显示,不滚动时隐藏。。。这个需要 js。。。但是换种 hover 时半透明显示,不 hover 时完全隐藏,这种效果也不错。。。
所以只有 2 最难实现。
另外,还尝试过把 width 设置为 0,但是也给它设置一个 outset 的 box-shadow,但是也没有显示出来,哪怕加了 overflow: visiable 也不行。。。
另外有个这个思路 http://www.zhangxinxu.com/wordpress/2015/01/css-page-scrollbar-toggle-center-no-jumping/
另外也可以试试 js 的 scroller。。。例如 github.com/forcedotcom/scrollerjs or cubiq/iscroll 前者的 demo 更好,后者的文档更好
*/
// 这个函数把定义任务与执行任务区分开。。。而且还会缓存任务结果,以及任务如果上次失败,则下次执行将会重新执行。。。
// 从而可以轻松构建全局可能会失败多次,但只会执行成功一次,的全局唯一懒执行任务
// 这个函数在理解时要注意不同的参数会返回不同的函数。。。也就是说需要预定义参数。。。memonize 不需要预定义参数
function task(fn) {
return function(...args) {
fn = fn.bind(this);
// 直接 Promise.reject 后面没直接接 catch 就会报错
// let p = Promise.reject(false);
let p;
// 增加强制刷新功能。。。
return (refresh) => {
if (refresh) {
p = fn(...args);
return p;
}
return (p || Promise.reject(false)).catch(e => {
p = fn(...args);
return p;
})
};
}
}
function better_task(fn) {
return function(...args) {
fn = fn.bind(this);
let p = null;
return refresh => ((refresh || !p) ? Promise.reject(false) : p).catch(e => {
p = fn(...args);
return p;
});
}
}
// ! task 得到的第一次的 promise 与 第二次的 promise 是不一样的。。。如果第一次的 promise throw 了,则第二次的是一个全新的 promise
// ! 事实上每次都是一个全新的 promise,因为 catch 就是生成一个新的 promise 对象
// ! 还应有一种只要两次请求是连在一起的,则保证返回同一个 promise 。。。这两种应该区分开。。。
// ! 也就是说第一种只缓存正确的 promise,第二种则仅仅是缓存 promise 无论对错
function cache_pending_promise(fn) {
let p = null;
return function(...args) {
fn = fn.bind(this);
if (!!p) {
return p;
}
p = fn(...args).then(a => {
p = null;
return a;
}).catch(e => {
p = null;
throw e;
});
return p;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment