'use strict';
/*
异步数据模块加载器
功能
1、加载器存在 主任务、副任务、子任务
newRequire 表示加载主任务,主任务并发执行,newRequire(param1),执行主任务的时候,暂停副任务,主任务结束后,再执行副任务。
onRequireFree 表示加载副任务,任务放队列,主任务结束后,副任务按顺序执行
require表示加载子任务,rule匹配后,执行ruleFunc(param1)
2、执行过程为:传入数据模块,匹配rule,执行ruleFunc,返回结果
param1表示模块数据,可为 String、Object、Number、Array,
defineRule表示定义规则,defineRule(rule,ruleFunc)
rule表示模块规则,可为 String、Function、Number,匹配param1则返回true,然后运行规则函数
ruleFunc表示规则函数,可为AsyncFunction、Function,返回结果
3、生命周期
相同的param1在同一个newRequire周期中,只会加载一次,默认缓存时间为0,也就是在下一个newRequire之前会被清理调缓存。
4、设置param1缓存时间
defineRule(rule,ruleFunc,0) 定义符合规则的所有模块,无缓存,优先级底
this.setCacheTime(param1,1000) 在ruleFunc函数内调用,设置缓存1秒,优先级高
demo
主任务
mainLoader.newRequire([
{
method:'random',
needFlag:true,
t:1
},
{
method:'random',
}
]).then(function (res) {
console.log(res)
}).catch(function (e) {
console.log(e)
})
=》[ { flag: 'S',
startTime: 1585545204173,
data: 1585545204475,
endTime: 1585545204475 },
1585545204777 ]
副任务
mainLoader.onRequireFree({
method:'task1',
}).then(function (res) {
console.log(res)
}).catch(function (e) {
console.log(e)
})
=》完成任务 [ 'task1:1585547219188', 'clearMoreCache:59' ]
*/
//主任务
class NRequire {
isType(obj,str){
return Object.prototype.toString.call(obj) === '[object '+str+']';
}
constructor(loader){
this.loader=loader;
this.cacheMap={};//缓存
this.startTimeMap={};
this.endTimeMap={};
//获取没过期的缓存
const time=new Date().getTime();
for(let url in loader.cacheMap){
if(this.isType(loader.moduleCacheTime[url],'Number')&&time<loader.endTimeMap[url]+loader.moduleCacheTime[url]){
this.cacheMap[url]=loader.cacheMap[url];
}else{
delete loader.moduleCacheTime[url];
loader.clearCache(url)
}
}
}
//加载模块
async require(param1){
//是否匹配到规则
const {key,index}=this.loader.matchRule(param1);
//需要缓存
if(index>-1){
let res;
const rulFunc=this.loader.ruleFuncs[index];
const rulTime=this.loader.ruleCacheTimes[index];
//匹配缓存,同时缓存在有效期
if(typeof this.cacheMap[key]!=='undefined'){
return this.cacheMap[key];
}
if(this.isType(rulTime,'Number')){
this.loader.moduleCacheTime[key]=rulTime;
}
if(this.isType(rulFunc,'AsyncFunction')){
res=await this.loader.startKey(key);
if(!res){
this.startTimeMap[key]=new Date().getTime();
try {
res=await rulFunc.call(this,param1);
}catch (e) {
throw e;
}
this.cacheMap[key] = res;
//缓存时间
this.endTimeMap[key]=new Date().getTime();
}
this.loader.endKey(key,res)
}else if(this.isType(rulFunc,'Function')){
res=rulFunc.call(this,param1);
this.cacheMap[key] = res;
}else{
res=rulFunc;
this.cacheMap[key] = res;
}
//缓存放入loader中
if(this.loader.moduleCacheTime[key]>0){
this.loader.cacheMap[key]=res;
this.loader.startTimeMap[key]=this.startTimeMap[key];
this.loader.endTimeMap[key]=this.endTimeMap[key];
}
return res;
}else{
return param1;
}
}
//设置模块缓存时间
setCacheTime(param1,cacheTime){
const item=this.loader.matchRule(param1);
if(this.isType(cacheTime,'Number')){
this.loader.moduleCacheTime[item.key]=cacheTime;
}
}
}
//AMD模块缓存加载器
class AMDLoader{
isType(obj,str){
return Object.prototype.toString.call(obj) === '[object '+str+']';
}
async startKey(key){
this.willI[key]=this.willI[key]||0;
this.curI[key]=this.curI[key]||0;
this.willI[key]++;
if(this.willI[key]>this.curI[key]+1){
return await new Promise((res)=> {
this.loadBack[''+key+this.willI[key]]=res;
})
}
}
endKey(key,res){
if(this.curI[key]<this.willI[key]){
this.curI[key]++;
while (this.curI[key]<this.willI[key]){
this.curI[key]++;
this.loadBack[''+key+this.curI[key]](res);
delete this.loadBack[''+key+this.curI[key]];
}
}
}
constructor(){
//配置
this.rules=[];
this.ruleFuncs=[];
this.ruleCacheTimes=[];
this.cacheMap={};//永久缓存,最大100
this.moduleCacheTime={};//临时缓存时间
this.startTimeMap={};
this.endTimeMap={};
this.nearTimeMap={};
//异步工具
this.willI={};
this.curI={};
this.loadBack={};
this.running=0;
this.actionArr=[];
}
//主任务
async newRequire(param1){
this.running++;
const nQest=new NRequire(this);//主任务
try {
const res=await nQest.require(param1);
this.running--;
return res;
}catch (e) {
let obj=this.isType(e,'Object')&&e.logType==='_error'?e:{
msg:e,
logType:'error',
bizData:param1,
};
this.running--;
if(this.running===0){
//执行副任务
this.onRequireFree()
}
//内部错误
// this.log(obj)
throw obj.msg;
}
}
//副任务
async onRequireFree(param1){
if(param1){
this.actionArr.push(param1);
}
if(this.running>0){
console.log('存在主任务');
return []
}
const arr=[]
while (this.running===0&&this.actionArr.length>0){
const bizData=this.actionArr.shift();
const nQest=new NRequire(this);//主任务
try {
const res=await nQest.require(bizData)
arr.push(res);
}catch (e) {
arr.push(e);
}
}
return arr
}
clearCache(key){
delete this.cacheMap[key];
delete this.nearTimeMap[key];
delete this.startTimeMap[key];
delete this.endTimeMap[key];
}
defineRule(rule,ruleFunc,cacheTime){
this.rules.push(rule);
this.ruleFuncs.push(ruleFunc);
this.ruleCacheTimes.push(cacheTime);
}
//命中规则
matchRule(param1){
let key;//key必然是个字符或者数字
if(this.isType(param1,'String')){
key=param1
}else if(this.isType(param1,'Object')){
key=JSON.stringify(param1)
}else if(this.isType(param1,'Array')){
key=JSON.stringify(param1)
}else if(this.isType(param1,'Number')){
key=JSON.stringify(param1)
}
let index=-1;
let keyback;//params 返回值
for(let i=this.rules.length-1;i>-1;i--){
const rule=this.rules[i];
if(this.isType(rule,'Function')){
keyback=rule.call(this,param1);
if(keyback){
index=i;
break;
}
}else if(this.isType(rule,'String')||this.isType(rule,'Number')){
keyback=rule;
if(param1===rule){
index=i;
break;
}
}
}
if(index>-1){
if(this.isType(keyback,'String')){
key=keyback;
}
}
return {
index:index,
key:key,
keyback:keyback,
}
}
log(obj){
console.log('发邮件',obj)
if(obj.logType==='_error'){
}else if(obj.logType==='error'){
}
}
//定义数组加载,[name1,name2]
defineArr(){
this.defineRule(function (param1) {
if(this.isType(param1,'Array')){
return true;
}
},async function (param1) {
const arr1=[]
for(let i=0;i<param1.length;i++){
const res=await this.require(param1[i])
arr1.push(res)
}
return arr1
})
}
//定义对象加载 {name1:'name1',name2:'name2'}
defineObj(){
this.defineRule(function (param1) {
if(this.isType(param1,'Object')){
return true;
}
},async function (param1) {
const nobj={};
const arr1=[]
const arr2=[]
for(let k in param1){
arr1.push(k);
arr2.push(this.require(param1[k]));
}
const arr3=await Promise.all(arr2);
for(let i=0;i<arr1.length;i++){
nobj[arr1[i]]=arr3[i];
}
return nobj
})
}
}
module.exports=AMDLoader;