Javascript实现顺序语法(完整版)

首先我们来看这样一个需求:

有这样一组操作:pre,a1,a2,a3,b1,b2,b3,suf,每个操作都花费不确定的时长,这可能需要访问网络或者等待事件响应,总之我需要传入一个回调函数然后随它开心什么时候去调用。

假定我们的需求是:必须在pre回调完成后才能执行A和B,并且A和B各自需要保证执行顺序,而A和B之间则无需考虑顺序。在A和B都执行完之后,必须执行suf。用ES5的回调函数去实现它无疑是一件令人崩溃的事情。

现在来看看我是怎么做的:

new syn(function*(method){
	console.log('syn in');
	let pre = yield method.exc(callback, "pre", this);
	console.log(pre);

	method.syn(function*(m){
		yield m.exc(callback, "a1", this);
		yield m.exc(callback, "a2", this);
		yield m.exc(callback, "a3", this);
		return "你开心就好";
	});
	method.syn(function*(m){
		let [w1] = yield m.exc(callback, "b1", this);
		let w2 = yield m.exc(callback, "b2", this);
		let w3 = (yield m.exc(callback, "b3", this))[0];
		return w1+w2[0]+w3;
	});
	method.syn(function*(m){
		m.exc(callback, "c1", this);
		m.exc(callback, "c2", this);
		m.exc(callback, "c3", this);
		return yield m.muti();
	});
	let [A, B, C] = yield method.muti();
	console.log(A);
	console.log(B);
	console.log(C);

	method.exc(callback, "suf1", this);
	method.exc(callback, "suf2", this);
	let [suf1, suf2] = yield method.muti();
	console.log(suf1);
	console.log(suf2);
	console.log("syn out");
});

function callback(name, func) {
	console.log("执行函数:"+name);
	setTimeout(func, Math.ceil(Math.random()*2)*1000, "函数回调:"+name);
}

在上面的例子中我使用了A,B,C三组并行处理的数据,以便更清晰的表现函数执行过程:

在上述例子中,pre执行完毕时,对a1,b1,c1连续调用,其中A、B要求上一个调用有结果才发起下一个调用,C为同时调用,等待全部结果一起返回。

在syn块中,仅当上一个yield表达式取得结果后,下面的代码才能够运行

实际上syn的实现原理十分简单,只是利用了ES6的语法糖,其本质上依然是回调函数的嵌套,并没有开启新的线程。但采用syn块后,代码的可读性惨遭巨大提升。

以下是syn方法的具体代码:

function syn(func, onreturn=null) {
	let method = {};
	let it = func.call(func, method);

	let ly;
	let results;
	let count = 0;
	let callback = (index,result) =>{
		count--;
		if(ly.value) {
			results[index] = result;
			if(!count) {
				ly = it.next(results);
			}
		} else {
			ly = it.next(result);
		}
		if(onreturn&&ly.done) {
			//console.log(ly.done);
			onreturn(ly.value);
		}
	};
	
	// 返回之前请求的全部值
	method.muti = ()=>{results = new Array(count);return true;};

	// 特别的,如果对多路并发请求需要进行并行处理的,可以调用syn方法‘开启子线程’
	// syn方法应当配合muti使用
	method.syn = (fun)=>{
		let index = count++;
		new syn(fun, (v)=>{
			callback(index, v);
		});
		return false;
	};
	// 执行外部方法,此处必须使用function,不能使用箭头函数,否则arguments无法获取外部传入的参数
	method.exc = function(){
		let index = count++;
		let target = arguments[0];
		let args = [];
		for(let i=1; i<arguments.length; i++) {
			if(func==arguments[i]) {
				args.push(function(){
					callback(index, arguments);
				});
			} else {
				args.push(arguments[i]);
			}
		}
		target.apply(func, args);
		return false;
	};
	// 扩展
	method.next = (v)=>it.next(v);

	ly = it.next();
};
发布了11 篇原创文章 · 获赞 8 · 访问量 8853

猜你喜欢

转载自blog.csdn.net/qq_26946497/article/details/85055046