LazyMay:實現同步和異步任務的順序執行

在掘金看到的文章,流程控制同步和異步任務的順序執行,收益匪淺,工做中能用到。promise

一、實現如下效果

實現一個LazyMan,能夠按照如下方式調用:
LazyMan(「Hank」)輸出:
Hi! This is Hank!

LazyMan(「Hank」).sleep(10).eat(「dinner」)輸出
Hi! This is Hank!
//等待10秒..
Wake up after 10
Eat dinner~

LazyMan(「Hank」).eat(「dinner」).eat(「supper」)輸出
Hi This is Hank!
Eat dinner~
Eat supper~

LazyMan(「Hank」).sleepFirst(5).eat(「supper」)輸出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper

以此類推。

這是典型的JavaScript流程控制,問題的關鍵是如何實現任務的順序執行。在Express有一個相似的東西叫中間件,這個中間件和咱們這裏的吃飯、睡覺等任務很相似,每個中間件執行完成後會調用next()函數,這個函數用來調用下一個中間件。異步

對於這個問題,咱們也能夠利用類似的思路來解決,首先建立一個任務隊列,而後利用next()函數來控制任務的順序執行:函數

 

1.2 隊列方式實現

function _LazyMan(name){
  this.tasks=[];
  var self=this;
  var fn=(function(n){
    var name=n;
    return function(){
      console.log("Hi! this is "+name+"!");
      self.next();
    }
  })(name);
  this.tasks.push(fn);
  setTimeout(function(){
    self.next();
  },0);  // 在下一個事件循環啓動任務
}
/* 事件調度函數 */
_LazyMan.prototype.next=function(){
  var fn=this.tasks.shift();
  fn && fn();
}
_LazyMan.prototype.eat=function(name){
  var self=this;
  var fn=(function(name){
    return function(){
      console.log("Eat "+name+" ~");
      self.next()
    }
  })(name);
  this.tasks.push(fn);
  return this; // 實現鏈式調用
}
_LazyMan.prototype.sleep=function(time){
  var self=this;
  var fn=(function(time){
    return function(){
      setTimeout(function(){
        console.log("Wake up after "+time+" s!");
        self.next();
      },time*1000);
    }
  })(time);
  this.tasks.push(fn);
  return this;
}
_LazyMan.prototype.sleepFirst=function(time){
  var self=this;
  var fn=(function(time){
    return function(){
      setTimeout(function(){
        console.log("Wake up after "+time+" s!");
      },time*1000);
    }
  })(time);
  this.tasks.unshift(fn);
  return this;
}
/* 封裝 */
function LazyMan(name){
  return new _LazyMan(name);
}

 

1.3 promise方式實現

lazyman裏邊含有鏈式調用,那麼每個子任務 return this;這個程序支持任務優先順序,那麼就須要兩個貫穿全場的Promise對象:第一,普通順序promise;第二,插入順序promise,同時插入順序是阻塞普通順序的,代碼以下:
function _LazyMan(name){
  this.orderPromise=this.newPromise(); // 定義順序promise對象
  this.insertPromise=this.newPromise(); // 定義插入promise對象
  this.order(function(resolve){
    console.log(name);
    resolve();
  })
}

_LazyMan.prototype={
  /*實例化promise對象工廠*/
  newPromise:function(){
    return new Promise(function(resolve,reject){
      resolve();
    })
  },
  order:function(fn){
    var self=this;
    this.orderPromise=this.orderPromise.then(function(){
      return new Promise(function(resolve,reject){
        //若是有insertPromise,阻塞orderPromise.
        self.fir?self.insertPromise.then(function(){
          fn(resolve)
        }):fn(resolve)
      })
    })
  },
  insert:function(fn){
    var self=this;
    this.fir=true;
    this.insertPromise=this.insertPromise.then(function(){
      return new Promise(function(resolve,reject){
        fn(resolve);
        self.fir=false;
      })
    })
  },
  sleepFirst:function(time){
    this.insert(function(resolve){
      setTimeout(function(){
        console.log('wait '+time+' s,other logic');
        resolve();
      },time*1000)
    })
    return this;
  },
  eat:function(something){
    this.order(function(resolve){
      console.log(something+' ~~');
      resolve();
    })
    return this;
  },
  sleep:function(time){
    this.order(function(resolve){
      setTimeout(function(){
        console.log('sleep '+time+' s');
      },time*1000);
    })
    return this;
  }
}

//接口封裝。
function LazyMan(name) {
    return new _LazyMan(name);
}
//調用測試
LazyMan(‘RoryWu‘).firstTime(1).sleep(2).firstTime(3).eat(‘dinner‘).eat(‘breakfast‘);
// 彈出:
// wait 1 s, other logic
// wait 3 s, other logic
// RoryWu
// sleep 2 s
// dinner~~
// breakfast~~

 

原文地址:http://www.javashuo.com/article/p-mphlibjy-ee.htmlpost

相關文章
相關標籤/搜索