Node.js与Golang使用感觉与小结【三】--JS异步流程控制(序列模式、并发模式、有限...

Node.js与Golang使用感觉与小结 php

目录 前端

1、互联网的基石TCP/IP协议 node

2、HTTP服务器编写与编程语言无关 程序员

3、构建HTTP服务器须要掌握的知识点 数据库

4、HTTP协议基础 编程

5、Node.js简介 后端

6、是前端选择,仍是后端的福音? 浏览器

7、Node.js与传统php-fpm模式之间的对比 服务器

8、安装Node.js 网络

9、让浏览器读懂你的心--Content-Type

10、向浏览器发送文件

11、Node.js异步流程控制(序列模式、并发模式、有限并发模式)

12、静态资源文件的简单优化

十3、如今还需少些什么?

十4、Golang 简介

十5、为何要用Golang 

十6、安装Golang开发环境

十7、如何使用Golang 编写一个HTTP服务器?

十8、Golang http包与Node.jshttp模块对比


11、Node.js异步流程控制(序列模式、并发模式、有限并发模式)

   Javascript在基本语法上与其它大部份C派生的语言没有太多区别,你可能很容易从其它语言过分到Javascript。不少从其它语言转到Javascript来的用户,在用一段时间以后极可能对这门语言又爱又恨,特别是对于异步流程的控制。

  对于大部份异步编程的模型来讲,大可能是事件驱动型且是基于进程来编码。这样为咱们带来了诸多好处,咱们没必要去处理为了实现一样目的而作的多线程模型里面的问题。多线程编程里面,因为多个线程访问的内存块是同样的,因此可能会出现死锁、共享竞争等问题。

   异步编程是什么昵?打个比方,你须要准备一个丰富的晚餐,其中有炒菜与熬汤。若是是阻塞式同步编程的话,你须要先去炒菜,等菜炒好了,而后在去熬汤。在炒菜的过程当中你不能在作其它事情,只有两样都好了的时候你才能开始你的晚餐。那异步会怎么作昵?能够一边熬汤,一边炒菜。菜炒好的时候,可能汤也好了。而后你就能够开动了。若是以每个步骤的时间来计算的话,二者的时间成本里面显然异步要能作的事情更多。

     阻塞式同步编程:炒菜(5分钟)+熬汤(30分钟)=开饭时用了35分钟

     异步式编程模型:【炒菜(5分钟)熬汤(30分钟)】=开饭时用了30分钟

     经过以上的例子能够知道异步编程模型在彻底任务的时间比以及时间利用上要高效的多。

研究异步流处理的意义



   异步流程控制很差,很容易写出巢式风格代码,随着项目的深刻与功能的扩展会发现愈来愈难以维护,或许这也是不少用不习惯JS的程序员不喜欢 JS的一个缘由 之一吧。

async1(function(input, result1) {

 async2(function(result2) {

    async3(function(result3) {

      async4(function(result4) {

       async5(function(output) { // do something with output });

        });

      });

    });

   })

以上这种代码即是咱们能够在某些程序员同窗中能够看到过的代码,特别是操做数据库部份常常容易出现这样的代码。之前一个同事说用过Node.js开发过一次程序后就不想再次开发程序,由于已经受够了这种难以维护的代码。当时我向他推荐了一些相似如AsyncjsStep之类的流程控制的库,最后那个项目是否采用就不得而知。

巢式风格的代码 可能引发的问题


解决之道

目前社区有三种观点:

(一)

     将代码分离再分离。虽然仍是有存在回调函数的问题,可是代码的复杂度获得必定的下降。举例而言(nodejs为例,但异步流程控制问题并非NODEJS的专利)

     var http=require(‘http);

     http.createServer(function(request,response){

     response.writeHead(200,{‘Content-Type:text/plain});

     response.write(‘hello);

     response.end();

     }).listen(80,’127.0.0.1);

    上面代码看似没有什么问题,可是若是这个时候我要向浏览器端返回一个文件,若是文件没存在返回404。又若是我要增长数据库访问功能。若是代码全放到这个里面。那维护起来会是怎么样的状况!


      var http=require(‘http);

      function requesthander(req,res){

      res.writeHead(200,{‘Content,text/plain});

      res.wirte(‘hello);

     res.end();

   }

     http.createServer(requesthander).listen(80,’127.0.0.1);

     这种分离方法被早期的一些设计所使用,其主体思想是将巢状代码给展平,分离每一步逻辑。可是这个也带来了另外的问题。虽然实现了分享,可是代码之间过于松散,代码之间的关系必须层层深刻的去理解。

  (二)

     将代码进一步抽象,使用统一的库或工具包去组织代码,不破坏原有代码的逻辑与组织。就Javascript 世界来讲出现了不少优秀的库。如Setp,Async(如网易开源的游戏开发框架)之类的库,他们提供了丰富的流控制接口,利用这些接口方法你能够很好的组织或利用好你的代码,减轻开发的负担。

使用方式以下:

async.series(
    [
        function(callback) {

            callback(null, ‘Node.js);//第一个函数的执行结果传给下个
        },
        function(callback) {
            callback(null, ‘JavaScript);//第二个函数的执行结果在传给最后的回调函数
        },
    ],
    function(err, response) {
        // response is [‘Node.js, JavaScript最后的结果收集。
    }
);

 

三)

  编译执行。是的,其大概思路是将已有的代码再经过某种方式编译一式,最终实现异步的功能。好比国内老赵的Jscex.虽然本人不太喜欢这种风格的方试,可是仍是向你们简单介绍一下其代码风格。Eval的使用以及代码组织方式让我放弃了使用此库。

下面开始这次的正题,介绍社区中经常使用的三种js异步流程控制模式

    不管网络上的代码怎么变化,提供了怎么样的接口,但目前来讲仍旧脱离不开如下三种模式。但愿经过简单的介绍能让您也写出一个本身的异步流程控制库或能了解其基本原理也不错。

    Series(串行模式)

                   -------每次只执行一个任务。

    Fully parallel(全并发模式)

                   -------一次性所有执行

    Limitedly parallel(限制并发模式)

                   -------每次按限制的个数执行并发任务。



异步处理库须要具有的功能

  一、可以提供控制函数集执行的方法。

  二、可以收集执行过程当中所产生的数据。

  三、提供特殊状况下的并发限制,由于在某些状况下对于并发数量是有控制的,不然可能会让你的系统吃不消。

  四、可以提供方法能在全部函数集确认执行成功后执行。


Series模式

   适用场景:对执行顺序有具体要求的情景。

   如查询多条数据库且数据库语句有依赖状况下  

   又好比说写文件(目录权限,文件是否存在,文件权限);

   特色:

   按顺序执行函数集

   在运行时每次只运行一个任务

   确保每次运行都在上一个任务完成后执行。

   每一步的数据是可控,可在下一个任务执行时被调用到(数据顺序性)。



Fully parallel模式

   适用场景:并发运行多个任务,当全部任务运行完通知回调方法。如多个I/O 

   做而且每一个时长不肯定的时候,可能须要这种模式。

   特色:

   并发运行多个任务,不用等待上一个任务执行完才执行。

   运算执行只能在回调函数中获得,由于并发模式不能确保执行的顺序。


Limited parallel模式

适用场景:系统资源有限,且每一个执行任务消耗资源较多。

 

特色:

 

并发运行多个限定任务,不用等待上一个任务执行完才执行。

 

运算执行结果只能在回调函数中获得,由于并发模式不能确保执行的顺序。

 

 

 

附三种模式的代码:、

/**
*  Series flow
*@param {Array} callbacks
*@param {Function} last
*@example series([fun1(next){
someFun();
next();//or next(value)
},fun2(next){
   someFun();
next();//or next(value)
}])
**/
function series(callbacks, last) {
  var results = [];
  function next() {
    var callback = callbacks.shift();
    if(callback) {
      callback(function() {
        results.push(Array.prototype.slice.call(arguments));
        next();
      });
    } else {
      last(results);
    }
  }
  next();
}
// Example task
function async(arg, callback) {
  var delay = Math.floor(Math.random() * 5 + 1) * 100; // random ms
  console.log('async with \''+arg+'\', return in '+delay+' ms');
  setTimeout(function() { callback(arg * 2); }, delay);
}
function final(results) { console.log('Done', results); }


series([
  function(next) { async(1, next); },
  function(next) { async(2, next); },
  function(next) { async(3, next); },
  function(next) { async(4, next); },
  function(next) { async(5, next); },
  function(next) { async(6, next); }
], final);
--------------------------------------------------------

function fullParallel(callbacks, last) {
  var results = [];
  var result_count = 0;
  callbacks.forEach(function(callback, index) {
    callback( function() {
      results[index] = Array.prototype.slice.call(arguments);
      result_count++;
      if(result_count == callbacks.length) {
        last(results);
      }
    });
  });
}
// Example task
function async(arg, callback) {
  var delay = Math.floor(Math.random() * 5 + 1) * 100; // random ms
 // console.log('async with \''+arg+'\', return in '+delay+' ms');
  for(var i =0;i<100000000;i++){


  }
  setTimeout(function() { callback(arg * 2); }, delay);
  console.log(+new Date());
 
}
function final(results) { console.log('Done', results); }


fullParallel([
  function(next) { async(1, next); },
  function(next) { async(2, next); },
  function(next) { async(3, next); },
  function(next) { async(4, next); },
  function(next) { async(5, next); },
  function(next) { async(6, next); }
], final);

-------------------------------------------------

function limited(limit, callbacks, last) {
  var results = [];
  var running = 1;
  var task = 0;
  function next(){
    running--;
    if(task == callbacks.length && running == 0) {
      last(results);
    }
    while(running < limit && callbacks[task]) {
      var callback = callbacks[task];
      (function(index) {
        callback(function() {
          results[index] = Array.prototype.slice.call(arguments);
          next();
        });
      })(task);
      task++;
      running++;
    }
  }
  next();
}
// Example task
function async(arg, callback) {
  var delay = Math.floor(Math.random() * 5 + 1) * 1000; // random ms
  console.log('async with \''+arg+'\', return in '+delay+' ms');
  setTimeout(function() {
    var result = arg * 2;
    console.log('Return with \''+arg+'\', result '+result);
    callback(result);
  }, delay);
}
function final(results) { console.log('Done', results); }


limited(2, [
  function(next) { async(1, next); },
  function(next) { async(2, next); },
  function(next) { async(3, next); },
  function(next) { async(4, next); },
  function(next) { async(5, next); },
  function(next) { async(6, next); }
], final);

---------------------------------------------

参考文献 :http://book.mixu.net/ 

 

==========================================================

关于做者:

网名:念念之间    现居:深圳

Email:jinfei121@qq.com

QQ:490821193

  从03年开始玩论坛,但正式写代码是前几年的事情。刚工做前两主要写php程序,目前主要专职写

Javascript.平时喜欢研究各类新鲜技术~~ 

  Node与Golang的粉丝~~

==========================================================

相关文章
相关标签/搜索