文档章节

合并请求之promise闭包

BryanYang
 BryanYang
发布于 2017/05/16 20:23
字数 483
阅读 213
收藏 0
import React from 'mui/reactjs/react';
import Callbacks from './callbacks';
import Request from './request';

const PAGE_PREFIX = 'ostium';
const API_PREFIX = 'api';

const cache = {};

const convertPermission = (keys, type = API_PREFIX)=> {
	const apis = keys.split(',');
	return apis.map(api => {
		api = api.trim();
		if (api) {
			return [type].concat(api.split('/')).join('-');
		}
	}).filter(api=>!!api);
};

const getPermissions = apis => Promise.all(apis.map(api => new Promise((resolve) => {
	if (!cache[api]) {
		cache[api] = Callbacks();
		Request(api).then(cache[api].fire).catch(() => {
			// 请求失败后,先标记为无权限,再清空缓存,下次可以重试
			cache[api].fire(false);
			delete cache[api];
		});
	}
	cache[api].add(result => {
		const obj = {};
		obj[api] = result;
		resolve(obj);
	});
}))).then(results => results.reduce((prev, current)=> Object.assign(prev, current), {}));

class Component extends React.Component {
	constructor(props) {
		super(props);
		this.init = this.init.bind(this);
		this.state = {
			authorized: false
		};
	}

	componentDidMount() {
		this.init(this.props);
	}

	componentWillReceiveProps(next) {
		if (!next.apiKeys || !next.pageKeys) {
			return;
		}
		if (next.apiKeys !== this.apiKeys || next.pageKeys !== this.pageKeys) {
			this.init(next);
		}
	}

	init(props) {
		const {apiKeys, pageKeys} = props;
		let permissions;
		if (apiKeys) {
			permissions = convertPermission(apiKeys);
		} else if (pageKeys) {
			permissions = convertPermission(pageKeys, PAGE_PREFIX);
		}
		if (permissions) {
			getPermissions(permissions).then(this.judge.bind(this)).catch(()=> {
			});
		}
	}

	judge(data) {
		this.setState({
			authorized: Object.values(data).every(v => v)
		});
	}

	static canUseApi = (apiKeys) => {
		return getPermissions(convertPermission(apiKeys)).then(data => {
			return {
				result: Object.values(data).every(v => v),
				data: data
			}
		});
	};

	static canUsePage = (pageKeys) => {
		return getPermissions(convertPermission(pageKeys, PAGE_PREFIX)).then(data=> {
			return {
				result: Object.values(data).every(v => v),
				data: data
			}
		});
	};

	render() {
		const { type='hide' } = this.props;
		let { authorized } = this.state;
		let { children } = this.props;

		if (!(children instanceof Array)) {
			children = [children];
		}
		return (
			<span style={this.props.style} className={this.props.className}>
			{
				authorized ? children :
					type == 'hide' ? '' :
						type == 'disabled' ?
							children.map(o => {
								return React.cloneElement(o, {disabled: true})
							}) :
							type == 'deny' ?
								children.map(o => {
									return React.cloneElement(o, {
										onClick: ()=> {
											o.props.onDeny && o.props.onDeny()
										}
									})
								}) : ''
			}
		</span>
		);
	}

}


// 每使用一次都要初始化。
export default Component;

Requese.js:

'use strict';
const fetch = require('ascm-comp/lib-fetch/index');

module.exports = (()=> {
	const cache = {};
	const host = (window._env_ === 'pre' || window._env_ == 'prod') ? 'xx' : 'yy';
	const url = `//${host}/webapi/permission/queryPermissions`;

	const request = (keys)=> {
		return new Promise((resolve, reject)=> {
			fetch({
				url,
				method: 'get',
				timeout: 1000 * 10,
				data: {
					_0: keys
				}
			}).then(res => {
				if (res.success && res.data) {
					resolve(res.data);
				} else {
					reject();
				}
			}).catch(()=> {
				reject();
			});
		})
	};

	const waitThenSend = (()=> {
		const map = {};
		const queue = [];
		let timer;

		const send = (list)=> {
			request(list).then((data)=> {
				Object.keys(data).forEach((key)=> {
					if (map[key] && map[key].resolve) {
						map[key].resolve(data[key]);
					}
				});
			}).catch(()=> {
				list.forEach((key)=> {
					if (map[key] && map[key].reject) {
						map[key].reject();
					}
					delete map[key];
					delete cache[key];
				});
			});
		};

		return (key, resolve, reject)=> {
			queue.push(key);
			map[key] = {
				resolve,
				reject
			};
			clearTimeout(timer);
			if (queue.length < 8) {
				timer = setTimeout(()=> {
					send(queue.splice(0, 8));
				}, 200);
			}
			else {
				send(queue.splice(0, 8));
			}
		};
	})();

	return key=> {
		if (!cache[key]) {
			cache[key] = new Promise((resolve, reject)=> {
				waitThenSend(key, resolve, reject);
			});
		}
		return cache[key];
	}
})();

Callbacks:

'use strict';

module.exports = ()=> {
	const queue = [];
	let fired = false;
	let result;
	return {
		add: callback=> {
			if (fired) {
				setTimeout(()=> {
					callback(result);
				}, 1);
			}
			else {
				queue.push(callback);
			}
		},
		fire: value => {
			fired = true;
			result = value;
			let t = queue.shift();
			while (t) {
				t(result);
				t = queue.shift();
			}
		}
	}
};

 

 

© 著作权归作者所有

BryanYang
粉丝 16
博文 165
码字总数 52036
作品 0
石景山
程序员
私信 提问
加载中

评论(0)

【Step-By-Step】高频面试题深入解析 / 周刊04

关于【Step-By-Step】 Step-By-Step (点击进入项目) 是我于 开始的一个项目,每个工作日发布一道面试题。 每个周末我会仔细阅读大家的答案,整理最一份较优答案出来,因本人水平有限,有误的...

刘小夕
2019/06/17
0
0
小邵教你玩转promise源码

前言:大家好,我叫邵威儒,大家都喜欢喊我小邵,学的金融专业却凭借兴趣爱好入了程序猿的坑,从大学买的第一本vb.net和自学vb.net,我就与编程结下不解之缘,随后自学易语言写游戏辅助、交易...

邵威儒
2018/08/13
0
0
PromiseKit基本使用及源码解析

Promise处理一系列异步操作的应用框架,能够保证顺序执行一系列异步操作,当出错时可以通过catch捕获错误进行处理。Promise框架也是很好的诠释了swift的面相协议编程以及函数式编程 两种类型...

不停奔跑的蜗牛
2019/11/14
0
0
前端基础

这一次,彻底弄懂 JavaScript 执行机制 本文的目的就是要保证你彻底弄懂javascript的执行机制,如果读完本文还不懂,可以揍我。 不论你是javascript新手还是老鸟,不论是面试求职,还是日常开...

掘金官方
2018/01/04
0
0
架构思维实现promise,大爷,来瞅瞅

小葵花课堂开课了惊不惊喜,期不期待,今天扯点promise的事情,主要为了学习,最重要的是按照正常人的逻辑器理解认识,promise的架构,不是死记硬背怎么去实现它 首先提出两个问题 为什么要手...

Dad
2018/09/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Flume概述及组成

Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并...

长臂猿猴
16分钟前
64
0
将较小的显示器切换到较大的显示器时,有没有办法重新绘制tmux窗口?

假设您使用Terminal.app通过ssh连接到远程服务器。 当您使用较大的分辨率监视器“tmux attach”时,您之前启动了tmux,它会在控制台周围绘制点。 它不适合新的窗口大小。 有没有办法重绘和清...

技术盛宴
24分钟前
34
0
在两个日期之间查找对象MongoDB

我一直在围绕在mongodb中存储推文,每个对象看起来像这样: {"_id" : ObjectId("4c02c58de500fe1be1000005"),"contributors" : null,"text" : "Hello world","user" : { "following......

javail
40分钟前
59
0
《aelf经济和治理白皮书》重磅发布:为DAPP提供治理高效、价值驱动的生态环境

2020年2月17日,aelf正式发布《aelf经济和治理白皮书》,这是aelf继项目白皮书后,在aelf网络经济模型和治理模式方面的权威论述。 《aelf经济和治理白皮书》描述了aelf生态中各个角色及利益的...

AELF开发者社区
51分钟前
53
0
战疫 | 高德工程师如何在3天上线“医护专车”

新冠状病毒肺炎疫情突袭,无数医护人员放弃与家人团聚,明知凶险,仍然奋战在一线。但因为武汉公交、地铁、网约车停运,医护人员上下班很难。白衣天使疾呼打车难。 (截图摘自《财经国家周刊...

amap_tech
今天
55
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部