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

本文探讨了在ES5和ES6环境下如何通过创新的syn方法实现复杂的异步任务调度,该方法通过模拟同步代码的流程,极大提升了代码的可读性和维护性,解决了传统回调地狱的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

有这样一组操作: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();
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值