每日一贴,今天的内容关键字为执行线程
jQuery中所支撑的步异模型为:
- Callbacks,回调函数队列。
- Deferred,迟延执行象对。
- Promise,是Deferred只暴露非状态改变方法的象对。
这些模型都很亮漂,但我想要一种更帅气的步异模型。
Thread?
我们晓得链式操纵是可以很好的表征运行序顺的(可以参考我的文章《jQuery链式操纵》),然而常通基于回调函数或者基于事件听监的步异模型中,码代的执行序顺不清晰。
Callbacks模型实际上似类一个自定义事件的回调函数队列,当触发该事件(用调Callbacks.fire())时,则回调队列中的有所回调函数。
Deferred是个迟延执行象对,可以注册Deferred胜利、失败或行进中状态的回调函数,然后通过触发应相的事件来回调函数。
这两种步异模型都似类于事件听监步异模型,实质上序顺依然是分离的。
当然Promise看似能供给我要需的西东,比如Promise.then().then().then()。但是,Promise虽然胜利用链式操纵确明了步异程编的序顺执行,但是没有环循,胜利和失败支分是通过部内码代肯定的。
个人认为,Promise是为了规范化后端nodejs中I/O操纵步异模型的,因为I/O状态只有胜利和失败两种状态,所以他是非常胜利的。
但在前端,要么只有胜利基本没有失败,要么不止只有两种状态,不当应定固只供给三种状态的案方,我认为应当供给可表征多状态的步异案方。
这个大家可以在something more看到。
我想要一种似类于线程的模型,我们在这里称为Thread,也就是他能序顺执行、也能环循执行、当然还有支分执行。
序顺执行
线程的序顺执行程流,也就是似类于:
do1();
do2();
do3();
do1(); wait(1000); //待等1000ms do2(); wait(1000); //待等1000ms do3(); wait(1000); //待等1000ms
Thread(). //获得线程 then(do1). //然后执行do1 wait(1000). //待等1000ms then(do2). //然后执行do2 wait(1000). //待等1000ms then(do3). //然后执行do3 wait(1000); //待等1000ms
环循执行
环循这很好懂得,比如for环循:
for(; true;){ dosomething(); wait(1000); }
Thread(). //获得线程 loop(-1). //环循开始,正数则示表环循正数次,正数则示表环循无穷次 then(dosomething). //然后执行do wait(1000). //待等1000ms loopEnd(); //环循结束
支分执行
支分也就是if...else,比如:
if(true){ doSccess(); }else{ doFail(); }
Thread(). //取得线程 right(true). //如果达表式准确 then(doSccess). //执行doSccess left(). //否则 then(doFail). //执行doFail leftEnd(). //left支分结束 rightEnd(); //right支分结束
明声变量
明声变量也就是:
var a = "hello world!";
Thread(). //到得线程 define("hello world!"). //将回调函数第一个参数设为hello world! then(function(a){alert(a);}); //获得变量a,alert出来
序顺执行实现案方
Thread实际上是一个打包函数Fn队列。
所谓打包函数就是将回调函数打包后发生的新的函数,举个例子:
function package(callback){
return function(){
callback();
// 干其他事件
}
}
这样我们就将callback函数打包起来了。
Thread供给一个fire方法来触发线程出取一个打包函数然后执行,打包函数执行前当回调Thread的fire方法。
那么我们就能够序顺执行函数了。
当初只要打包的时候置设setTimeout执行,则这个线程就能够实现wait方法了。
环循执行实现案方
环循Loop是一个Thread的变形,只不过在执行里头的打包函数的时候应用另外一种案方,通过添加一个指针出取,执行完后触发Loop继承,挪动指针出取下一个打包函数。
支分执行实现案方
支分Right和Left也是Thread的一种变形,开启支分的时候,主Thread会创立两个支分Right线程和Left线程,打包一个触发支分Thread的函数推入队列,然后当执行到该函数的时候判断触发哪个支分执行。
其中一个队列执行结束后回调主Thread,通知行进下一步。
例子
由于该案方和wind-asycn非常相似,所以我们拿wind.js中的clock例子行进改革看看其中的别差吧。
wind.js中的例子:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Clock - Wind.js Sample</title>
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<script src="http://www.cnblogs.com/../src/wind-core.js"></script>
<script src="http://www.cnblogs.com/../src/wind-compiler.js"></script>
<script src="http://www.cnblogs.com/../src/wind-builderbase.js"></script>
<script src="http://www.cnblogs.com/../src/wind-async.js"></script>
<script>
var drawHand = function(value, length) {
ctx.beginPath();
var angle = Math.PI * 2 * value / 60;
var x = Math.sin(angle) * length;
var y = Math.cos(angle) * length;
ctx.moveTo(100, 100);
ctx.lineTo(100 + x, 100 - y);
ctx.stroke();
}
var drawClock = function(time) {
if (!ctx) {
var h = time.getHours();
var m = time.getMinutes();
var s = time.getSeconds();
var text =
((h >= 10) ? h : "0" + h) + ":" +
((h >= 10) ? m : "0" + m) + ":" +
((h >= 10) ? s : "0" + s);
document.getElementById("clockText").innerHTML = text;
return;
}
ctx.clearRect(0, 0, 200, 200);
ctx.beginPath();
ctx.arc(100, 100, 90, 0, Math.PI * 2, false);
for (var i = 0; i < 60; i += 5) {
var angle = Math.PI * 2 * i / 60;
var x = Math.sin(angle);
var y = Math.cos(angle);
ctx.moveTo(100 + x * 85, 100 - y * 85);
ctx.lineTo(100 + x * 90, 100 - y * 90);
}
ctx.stroke();
drawHand(time.getSeconds(), 80);
drawHand(time.getMinutes() + time.getSeconds() * 1.0 / 60, 60);
drawHand(time.getHours() % 12 * 5 + time.getMinutes() * 1.0 / 12, 40);
}
var drawClockAsync = eval(Wind.compile("async", function(interval) {
while (true) {
drawClock(new Date());
$await(Wind.Async.sleep(interval));
}
}));
</script>
</head>
<body>
<canvas id="clockCanvas" height="200" width="200">
<div id="clockText" style="font-size:20pt;"></div>
</canvas>
<script>
var canvas = document.getElementById("clockCanvas");
var ctx = canvas.getContext ? canvas.getContext("2d") : null;
drawClockAsync(1000).start();
</script>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Clock - asThread.js Sample</title>
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<!-- 例子修改自wind.js -->
<script src="asThread.js"></script>
<script>
var drawHand = function(value, length) {
ctx.beginPath();
var angle = Math.PI * 2 * value / 60;
var x = Math.sin(angle) * length;
var y = Math.cos(angle) * length;
ctx.moveTo(100, 100);
ctx.lineTo(100 + x, 100 - y);
ctx.stroke();
}
var drawClock = function() {
var time = new Date()
if (!ctx) {
var h = time.getHours();
var m = time.getMinutes();
var s = time.getSeconds();
var text =
((h >= 10) ? h : "0" + h) + ":" +
((h >= 10) ? m : "0" + m) + ":" +
((h >= 10) ? s : "0" + s);
document.getElementById("clockText").innerHTML = text;
return;
}
ctx.clearRect(0, 0, 200, 200);
ctx.beginPath();
ctx.arc(100, 100, 90, 0, Math.PI * 2, false);
for (var i = 0; i < 60; i += 5) {
var angle = Math.PI * 2 * i / 60;
var x = Math.sin(angle);
var y = Math.cos(angle);
ctx.moveTo(100 + x * 85, 100 - y * 85);
ctx.lineTo(100 + x * 90, 100 - y * 90);
}
ctx.stroke();
drawHand(time.getSeconds(), 80);
drawHand(time.getMinutes() + time.getSeconds() * 1.0 / 60, 60);
drawHand(time.getHours() % 12 * 5 + time.getMinutes() * 1.0 / 12, 40);
}
Thread(). // 应用主线程线程
loop(-1). // 正数示表环循无穷多次,如果是正数n,则示表n次环循
then(drawClock). // 环循中运行drawClock
wait(1000). // 然后待等1000ms
loopEnd(); // 环循结束
// 线程定义结束
</script>
</head>
<body>
<canvas id="clockCanvas" height="200" width="200">
<div id="clockText" style="font-size:20pt;"></div>
</canvas>
<script>
var canvas = document.getElementById("clockCanvas");
var ctx = canvas.getContext ? canvas.getContext("2d") : null;
Thread().run(); // 运行线程
</script>
</body>
</html>
Something more?
- 将事件成当支分理处
我们供给了on方法将事件转成支分来执行。
举个例子面页有个按钮“点我”,但是我们望希打开面页5秒内单击没效有,5秒后示显“请点击按钮”后,单击才会现出“你胜利点击了”。
应用on支分是这样的:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>on - asThread.js Sample</title> <meta http-equiv="X-UA-Compatible" content="IE=9" /> <script src="asThread.js"></script> </head> <body> <button id = "b">点我</button> <script> var ele = document.getElementById("b"); Thread(). // 取得线程 then(function(){alert("请点击按钮")}, 5000). //然后等5秒示显"请点击按钮" on(ele, "click"). // 事件支分On开始,如果ele触发了click事件 then(function(){alert("你胜利点击了")}). //那么执行你胜利点击了 onEnd(). // 事件支分On结束 then(function(){alert("都说可以的了")}). // 然后弹出"都说可以的了" run(); //启动线程 </script> </body> </html>
function addEvent(__elem, __type, __handler){ //添加听监 } function removeEvent(__elem, __type, __handler){ //删除听监 } Thread(). on(ele, "success", addEvent, removeEvent). then(function(){alert("胜利!")}). onEnd(). run();
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>on - asThread.js Sample</title> <meta http-equiv="X-UA-Compatible" content="IE=9" /> <script src="asThread.js"></script> </head> <body> <button id = "b">点我</button> <button id = "c">点我</button> <script> var ele0 = document.getElementById("b"), ele1 = document.getElementById("c"); Thread(). // 取得线程 then(function(){alert("请点击按钮")}, 5000). //然后等5秒示显"请点击按钮" on(ele0, "click"). // 事件支分On开始,如果ele0触发了click事件 then(function(){alert("你胜利点击了")}). //那么执行你胜利点击了 on(ele1, "click"). // 事件支分On开始,如果ele1触发了click事件 then(function(){alert("你胜利点击了")}). //那么执行你胜利点击了 onEnd(). // 事件支分On结束 then(function(){alert("都说可以的了")}). // 然后弹出"都说可以的了" run(); //启动线程 </script> </body> </html>
- 开拓多个线程
一个线程不够用?只要输入名字就能够开拓或者到得线程了。
系统会主动初始化一个主线程,当不传参数时就直接返回主线程:
Thread() //到得主线程
Thread("hello") //到得名字是hello的线程
Thread("hello") //到得hello线程
Thread("hello").del();
- setImmediate
IE10经已供给了setImmediate方法,而其他代现浏览器也可以模拟该方法,其理原是推倒线程末了,使得浏览器画面能渲染,到得比setTimeout(0)更快的响应。
我们通过口接.imm来供给这一功能。比如:
Thread(). imm(function(){alert("hello world")}). run();
所以如果你应用多个Thread(伪多线程),而又望希确保线程是并行运行的,那么请应用.imm来替换.then。
当然对于老版IE,只能用setTimeout(0)替换了。
- 支分参数可是以函数
支分Right传的参数如果只是布尔值定肯很不爽,因为这意味着支分是静态的,在初始化时候就定决了,但我们望希支分能在执行到的时候再判断是走Right还是Left,所以我们供给了传参可是以函数(但是函数返回值要需是布尔值,否则……╮(╯▽╰)╭也会转成布尔值的……哈哈)。比如:
fucntion foo(boolean){ return !boolean; } Thread(). define(true). right(foo). then(function(){/*这里不会运行到*/}). rightEnd(). run();
Enjoy yourself!!
目项地址
https://github.com/miniflycn/asThread
文章结束给大家分享下程序员的一些笑话语录: 程序语言综述
CLIPPER 程序员不去真的猎捕大象,他们只是购买大象部分的库然后花几年的时间试图综合它们。
DBASE 程序员只在夜间猎捕大象,因为那时没人会注意到他们还在使用石弓。
FOXPRO 程序员开始使用更新更好的步枪,这使他们花掉比实际狩猎更多的时间学习新的射击技术。
C 程序员拒绝直接购买步枪,宁可带着钢管和一个移动式机器车间到非洲,意欲从零开始造一枝完美的步枪。
PARADOX 程序员去非洲时带着好莱坞关于猎捕大象的电影剧本,他们认为照剧本行事就会逮到一头大象。
ACCESS 程序员在没有任何猎象经验的经验下就出发了,他们穿着华丽的猎装、带着全部装备,用漂亮的望远镜找到了大象,然后发觉忘了带扳机。
RBASE 程序员比大象还要稀少,事实上,如果一头大象看到了一个RBASE程序员,对他是个幸运日。
VISUAL ACCESS 程序员装上子弹、举起步枪、瞄准大象,这使大象感到可笑,究竟谁逃跑。他们无法抓住大象,因为由于他们对多重控制的偏爱,他们的吉普车有太多的方向盘因而无法驾驶。
ADA、APL和FORTRAN 程序员与圣诞老人和仙女一样是虚构的。
COBOL 程序员对和自己一样濒临灭绝的大象寄予了深切的同情。