es6,promise,generator,next,yield与koa

时间:2021-09-05 23:29:44

es6里有了很多新特性

promise是一种形式,使用promise可以让异步的代码像同步代码,从而更符合人类的思维方式,使回调函数的写法变得轻松

在函数中使用promise,一般是return一个用promise包裹的函数,如:

 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/

generator就是一个状态机函数,在generator函数内部用yield关键字进行分块,在调用generator函数时,用.next()方法进入下一个状态:

 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两个元素的对象。

引用http://web.jobbole.com/82903/的话:

每当 Generator 函数执行遇到 yield 表达式时,函数的栈帧 — 本地变量,函数参数,临时值和当前执行的位置,就从堆栈移除,但是 Generator 对象保留了对该栈帧的引用,所以下次调用 .next() 方法时,就可以恢复并继续执行。

然而generator并不是多线程,

在支持多线程的语言中,同一时间可以执行多段代码,并伴随着执行资源的竞争,执行结果的不确定性和较好的性能。而 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的前的对象。

这里实际上就是把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函数继续往下走。