Skip to content

异步流程控制器pjs的渐进式实现 #17

@noneven

Description

@noneven

异步流程控制器实现

//最终效果:
pjs.when(["A","B"],(val)=>{
	console.log(val);
});
pjs.when(["A","C"],(val)=>{
	console.log(val);
});
setTimeout(()=>{
	pjs.trigger("A", "dataA");
},1000)
setTimeout(()=>{
	pjs.trigger("B", "dataB");
},2000)
setTimeout(()=>{
	pjs.trigger("C", "dataC");
},3000)

step1 简版实现

思路:调用when的时候将异步任务(A B)用数组存起来,并将异步回调用callback存储;然后当A/B异步任务完成时调用trigger方法把异步任务数组里面的A/B删除,并且检测异步任务队列是否为空,为空时调用callback。

// 最简版
var pjs = {};
var _tasks = []; var _callback;
pjs.when = function(tasks, callback){
	_tasks = tasks;
	_callback = callback;
};
pjs.trigger = function(task){
	_tasks.splice(task.indexOf(_tasks), 1);
	if(_tasks.length == 0){
		_callback();
	}
};

step2 trigger时支持传值

思路:在step1的基础上 每次trigger的时候将trigger的值存入一个map里面,最后执行回调的时候把这个map作为参数传入

// 支持传值
var pjs = {};
var _tasks = []; var _callback;var valMap = {};
pjs.when = function(tasks, callback){
	_tasks = tasks;
	_callback = callback;
};
pjs.trigger = function(task, val){
	_tasks.splice(task.indexOf(_tasks), 1);
	valMap[task] = val;
	if(_tasks.length == 0){
		_callback(valMap);
	}
};

step3 支持多个异步队列(多个when)

思路:每次调用when的时候用一个异步队列map存储多个when,每次trigger的时候在多个异步队列里面循环,删除每个异步队列的异步任务。相当于增加一个维度。

// 支持多个when
var pjs = {};
var uid = 0;
pjs.when = function(tasks, callback){
	tasksMap[++uid] = {
		tasks: tasks,
		valMap: {},
		callback: callback
	};
};
pjs.trigger = function(task, val){
	for(var k in tasksMap){
		var uidtask = tasksMap[k].tasks;
		if(uidtask.indexOf(task)==-1) continue;

		var uidvalmap = tasksMap[k].valMap;
		var uidcallback = tasksMap[k].callback;
		uidvalmap[task] = val;
		uidtask.splice(uidtask.indexOf(task), 1);
		if(uidtask.length==0){
			uidcallback(uidvalmap);
		}
	}
}

step4 优化

思路:step3里面存在一个问题,就是每次trigger都会去循环所有的异步队列,即使该异步队列里面没有trigger的任务,所以在这里需要做一个改进,在when的时候我们以异步任务为key存储它关联的异步队列(uid),在trigger的时候只需要去循环它关联的异步队列uid,优化循环

var pjs = {};
var tasksMap = {};var evtMap = {};
var uid = 0;

pjs.when = function(tasks, callback){
	tasksMap[++uid] = {
		tasks: tasks,
		valMap: {},
		callback: callback
	};
	tasks.map(function(evt, index){
		var evtuid = evtMap[evt];
		evtuid?evtuid.push(uid):evtuid = [uid];
	});
};
pjs.trigger = function(task, val){
	for(var i=0;i<evtMap[task].length;i++){
		var uid = evtMap[task][i]
		var uidtask = tasksMap[uid].tasks;
		if(uidtask.indexOf(task)==-1) continue;

		var uidvalmap = tasksMap[uid].valMap;
		var uidcallback = tasksMap[uid].callback;
		uidvalmap[task] = val;
		uidtask.splice(uidtask.indexOf(task), 1);
		if(uidtask.length==0){
			uidcallback(uidvalmap);
		}
	}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions