---恢復內容開始---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