es6裏有了不少新特性javascript
promise是一種形式,使用promise可讓異步的代碼像同步代碼,從而更符合人類的思惟方式,使回調函數的寫法變得輕鬆html
在函數中使用promise,通常是return一個用promise包裹的函數,如:java
1 function t(arg){ 2 //準備工做,處理等 3 // 。。。 4 var istrue =arg+1 5 //處理結束 6 return new promise(function(resolve,reject{ 7 //斷定並返回 8 if(istrue!='3'){ 9 console.log(istrue) 10 resolve(); 11 }else{ 12 reject(); 13 } 14 })) 15 } 16 t(3) 17 .then(t(1)) 18 .then(t(8)) 19 .then(t(2))
關於promise函數的感性認識能夠猛擊:http://www.zhangxinxu.com/wordpress/2014/02/es6-javascript-promise-%E6%84%9F%E6%80%A7%E8%AE%A4%E7%9F%A5/es6
generator就是一個狀態機函數,在generator函數內部用yield關鍵字進行分塊,在調用generator函數時,用.next()方法進入下一個狀態:web
1 function* quips(name) { 2 yield "hello " + name + "!"; 3 yield "i hope you are enjoying the blog posts"; 4 if (name.startsWith("X")) { 5 yield "it's cool how your name starts with X, " + name; 6 } 7 yield "see you later!"; 8 } 9 > var iter = quips("jorendorff"); 10 [object Generator] 11 > iter.next() 12 { value: "hello jorendorff!", done: false } 13 > iter.next() 14 { value: "i hope you are enjoying the blog posts", done: false } 15 > iter.next() 16 { value: "see you later!", done: false } 17 > iter.next() 18 { value: undefined, done: true }
每次調用.next()函數的返回值是一個包含value和done兩個元素的對象。promise
引用http://web.jobbole.com/82903/的話:多線程
每當 Generator 函數執行遇到 yield 表達式時,函數的棧幀 — 本地變量,函數參數,臨時值和當前執行的位置,就從堆棧移除,可是 Generator 對象保留了對該棧幀的引用,因此下次調用 .next() 方法時,就能夠恢復並繼續執行。
然而generator並非多線程,app
在支持多線程的語言中,同一時間能夠執行多段代碼,並伴隨着執行資源的競爭,執行結果的不肯定性和較好的性能。而 Generator 函數並非這樣,當一個 Generator 函數執行時,它與其調用者都在同一線程中執行,每次執行順序都是肯定的,有序的,而且執行順序不會發生改變。與線程不一樣,Generator 函數能夠在內部的 yield 的標誌點暫停執行。
使用generator來作回調:框架
function delay(time, callback){ setTimeout(function(){ callback("Slept for "+time); },time); } function run(generatorFunction) { var generatorItr = generatorFunction(resume); function resume(callbackValue) { generatorItr.next(callbackValue); } generatorItr.next() } run(function* myDelayedMessages(resume) { console.log(yield delay(1000, resume)); console.log(yield delay(1200, resume)); });
解釋一下:generator函數返回一個迭代器,這裏就是generatorItr,它在resume裏被調用使用next(callbackValue)方法,將resume的參數callbackValue傳入給yield的前的對象。koa
這裏實際上就是把yield後語句的返回值傳給yield前的對象,而且持續轉進到下一個狀態。
koa就實現了這個run方法的機制,不用咱們寫了
1 'use strict' 2 var koa = require('koa') 3 var app = koa(); 4 var fs =require('fs') 5 6 app.use(function *(next){ 7 var content = yield readFileAsync('./index.html'); 8 console.log('this is '+content); 9 console.log('body. '+content); 10 this.body=content; 11 }); 12 13 function readFileAsync(fpath){ 14 return new Promise(function(resolve,reject){ 15 fs.readFile(fpath,'utf-8',function(err,content){ 16 if(err) reject(err) 17 else { 18 resolve(content)} 19 }) 20 }) 21 } 22 var port = 3001; 23 app.listen(port) 24 console.log('listening on port '+ port)
網上有一些本身實現了簡單的koa框架的,咱們能夠參考這些代碼,來總結koa框架的使用規律。好比一個實現了koa 中的co函數及使用例子以下
1 function co(generator){ 2 var gen = generator(); 3 4 var next = function(data){ 5 var result = gen.next(data); 6 7 if(result.done) return; 8 9 if (result.value instanceof Promise) { 10 console.log("in if (result.value instanceof Promise)"); 11 result.value.then(function (d) { 12 next(d); 13 }, function (err) { 14 next(err); 15 }) 16 }else { 17 next(); 18 } 19 }; 20 21 next(); 22 } 23 co(function*(){ 24 var text1 = yield new Promise(function(resolve){ 25 console.log("in 1st Promise"); 26 setTimeout(function(){ 27 resolve("I am text1"); 28 }, 1000); 29 }); 30 31 console.log(text1); 32 33 var text2 = yield new Promise(function(resolve){ 34 setTimeout(function(){ 35 resolve("I am text2"); 36 }, 1000); 37 }); 38 39 console.log(text2); 40 });
koa use 方法中的參數必須是一個generator函數或者能夠返回一個generator函數對象,這個函數假設爲g,g裏用yield關鍵字進行異步調用,而yield後必須返回一個promise對象,由於在co函數裏,須要調用yield 返回的對象的then方法進行參數傳遞或者錯誤信息傳遞。
co函數負責取到yield返回promise對象的運行結果,並傳遞給yield關鍵字以前的值,隨後調用generator函數的next方法推進generator函數繼續往下走。