执行线程一种模仿线程的Javascript异步模型设计&实现

每日一贴,今天的内容关键字为执行线程

    

    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,do2,do3。因为这是步异模型,所以我们望希能添加wait方法,即似类于:
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);
}
行进无穷次环循执行do,并且每次都迟延1000ms。则其链式达表当应是这样的:
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>
自定义事件也可以哦,只要在.on时候传进去注册听监函数,和删除听监函数了行就。比如:
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线程
默许只最多只供给10个线程,所以用完记得删掉:
Thread("hello").del();

    

  • setImmediate

    

    IE10经已供给了setImmediate方法,而其他代现浏览器也可以模拟该方法,其理原是推倒线程末了,使得浏览器画面能渲染,到得比setTimeout(0)更快的响应。

    我们通过口接.imm来供给这一功能。比如:

Thread().
imm(function(){alert("hello world")}).
run();
这方法和.then(fn)不太一样,.then(fn)是可能塞阻前当浏览器线程的,但.imm(fn)是将理处推到浏览器擎引队列末了,排到队了在运行。

    所以如果你应用多个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 程序员对和自己一样濒临灭绝的大象寄予了深切的同情。


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值