Promise/Generator/Co

---恢復內容開始---javascript

 

這三個都是爲解決回調而生的, 最近在學習Koa框架, Koa框架主要就是將異步的寫法變成的同步, 解決了回調地獄的問題,也易於流程的控制, 因而找了不少篇文章學習, 終於有點感悟了~ >-<java

一、Promise 

      看名字,Promise(承諾), 很容易聯想到, 這個應該是異步操做結果的承諾, 就像數據庫操做, 咱們要先去find(), find到了以後就去save(), 那咱們承諾find到結果後就去save, 這樣就實現了異步寫法變同步寫法 Promise.then(DB.save(){}) 這樣,咱們就解決了一些些回調函數的問題了es6

      仍是比較正式一些介紹一下Promise:這是一個對象, 用於傳遞異步操做的信息。數據庫

  它的特色json

一、Promise對象表明一個異步操做, 有三種狀態 Pending(進行中) Resolve(已完成) Reject(已失敗) 只有異步操做的結果能夠決定當前的狀態
二、Promise對象的狀態改變: Pending=>Resolved , Pending=>Rejected

  基本用法promise

var promise = new Promise(function (resolve, reject) {
    if (find得了數據成功) {
        resolve(數據);
    } else {
        reject(err)
    }
})
 
 
//經過Generator部署Ajax操做
function *main() {
    var result = yield request('...');
    var resp = JSON.parse(result);
    console.log(resp.value);
}
function request(url) {
    makeAjaxCall(url, function(response) {
        it.next(response);//參數加上response, 做爲result的值,不然返回的是undefined
    })
}
var it = next();
it.next();
//解決回調地獄
step1(function (value1) {
   step2(value1, function(value2) {
      dothing...     
   }) 
})

//若是用Promise改寫的化
Q.fcall(step1)
    .then(step2)//step1,2都是異步操做
    .then(function(){
       dosth... 
    }, function(err) {
       doerr... 
    })
    .done();

//用generator控制流程
function* longRunningTask() {
    try {
        var value1 = yield step1();
        var value2 = yield step2(value1);
    } catch(e) {
        s....
    }
}
//這個函數按次序自動執行全部步驟
function scheduler(task) {
    setTimeout(function() {
        var taskObj = task.next(task.value);
        if (!taskObj.done) {
            task.value = taskObj.value;
            scheduler(task)'
        }
    }, 0);
}

 

 
 

 

/Promise實例生成後, 用then方法分別制定Resolve和Reject的回調函數
promise.then(functioin(數據) {
    dealWith(數據);
    }, function(err) {
    handout)(err)
    }
)
//異步加載圖片
function loadImageAsync(url) {
    return new Promise(function(resolve, reject) {
        var image = new Image(); //異步加載一張圖片
        image.onload = function() {
            resolve(image);//加載成功把image傳給承諾的下個函數做爲參數
        }
        image.onerror = function() {
            reject(new Error('Could not load image at + 'url');
        }
        image.src = url;
    })           
}
//異步操做的結果是另外一個異步操做
var p1 = new Promise(function (resolve, reject) {
    doSomething();
})
var p2 = new Promise(function (resolve, reject) {
    resolve(p1); //p2須要等待p1的狀態進行下一步操做, 等於數據庫的save須要等待find的狀態,這兩個就是兩個異步操做
})
//Promise.then
//上面的能夠用這個栗子改寫
DB.find('someFile').then(
    file => save(file.AAA)
).then(
    AAA => doSomething(AAA),
    err   => console.log(err)
);
//Promise.all用於將多個Promise包裝成一個實例
var promises = [1, 2, 3, 4, 5, 6, 7].map(function(id) {
    return getJSON(id + '.json'); //Promise函數
})
Promise.all(promises).then(function(posts) {
    do(posts);
}).catch(function(reason) {
}
//Generator和Promise
//Generator用於管理流程
function getFoo() {
    return new Promise(function(resolve, reject) {
        resolve('foo');//返回一個Promise對象
    })
}

var g = function *() {
    try{
        var foo = yield getFoo(); //迭代器到這裏纔會運行
        console.log(foo);
    } catch (e) {
        console.log(e);
    }
}
// 簡單的co
function run(generator) {
    var it = generator(); //生成迭代器實例
    function go(result) {
        if (result.done) {
            return result.value;
        }
        return result.value.then(function (value) {
            return go(it.next(value));
        }, function(err) {
            return go(it.throw(error));
        })'
    }
    go(it.next()); //啓動迭代器遍歷
}

run(g)

 

二、Generator

能夠把Generotor當作一個狀態機, 封裝了內部狀態框架

執行Generator函數返回一個遍歷器對象, 調用遍歷器對象的next方法可使得遍歷的指針向下走異步

//生成一個Generator對象
function *asd() {
    yield 'joe';
    yield 'chan';
    return 'done';
}
var asd = asd();
asd.next()
// { value: 'joe', done: false }

asd.next()
// { value: 'chan', done: false }

asd.next()
// { value: 'done', done: true }

asd.next()
// { value: undefined, done: true }

//遇到yield暫停後面的操做, yield後面的表達式的值做爲返回對象的value
//yield語句沒有返回值(老是返回undefined),next(arg)中的arg就被看成上一個yield語句的返回值
//上面最後一點的一個應用
function *foo(x) {
    var y = 2* (yield x);
    var z = yield y;
    return z+y
}
var foo = foo(5);
foo,next() //{value:5, done: false}
foo.next() //{value:NaN, done: false} //由於yield的返回值是undefined

foo.next(12) //{value: 24, done: false} //傳入參數看成上一次yield的返回值

 異步操做的同步化表達ide

function *loadUI() {
    showLoadingScreen();
    yield loaUIAsyncchoromously();//異步操做
    hideLoadingScreen(); //異步操做的後續操做(原來的回調函數)
}
var loader = loadUI();
//加載UI
loader.next();
...
//卸載UI
loader.next();

 

//經過Generator函數部署Ajax操做
function* main() {
  var result = yield request("http://...");
  var resp = JSON.parse(result);
    console.log(resp.value);
}//同步方式表達Ajax

function request(url) {
  makeAjaxCall(url, function(response){
    it.next(response);//response做爲result的值, 
  });
}

var it = main();
it.next();//開始遍歷迭代器

經典的回調hell函數

step1(function (value1) {
  step2(value1, function(value2) {
    dosth...
  });
});

//用Promise改寫上面的代碼
fcall(step1)
  .then(step2)
  .then(function (value2) {
    do...
  }, function (error) {
    doerr
  })
  .done();



//
Generator函數控制代碼運行流程
function* longRunningTask() { try { var value1 = yield step1(); var value2 = yield step2(value1);  //do... } catch (e) {  doerr } }//同步控制流程

scheduler(longRunningTask()); function scheduler(task) { setTimeout(function() { var taskObj = task.next(task.value); //異步操做  if (!taskObj.done) { task.value = taskObj.value scheduler(task); } }, 0); } 
 

參考

http://es6.ruanyifeng.com/#docs/generator

本站公眾號
   歡迎關注本站公眾號,獲取更多信息