es6 generator 和 promise

流程控制,generator,promise

promise

使用bluebird库,Promise包含then 方法存放回调.
由未完成态,转向 完成态(onFulfilled) 和 失败态(onRejected),使用 resolve和reject转换。
https://github.com/petkaantonov/bluebird/blob/master/API.md#api-reference

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var Promise = require('bluebird');

function getUser(name, pass, callback) {
// query database ...
setTimeout(function() {
// simulate long time operation
if (name === pass) {
callback(null, {
name: name,
pass: pass
});
}
else {
callback(new Error("can't find user ..."));
}
}, 1000);
}

var getUserAsync = function(name, pass) {
return new Promise(function(resolve, reject) {
console.log("doing new Promise",new Date);
getUser(name,pass,function(err,user){
if(err){
return reject(err);
}else{
resolve(user,name,pass);
}
});
});
}

exports.getUserAsync = getUserAsync;

console.log("before getUserAsync ...",new Date);
getUserAsync('zhang','zhang')
.then(function(user,name,pass){
console.log("got user back",new Date());
console.log(user,name,pass); // then() 添加的回调只接受一个参数,此处 name ,pass 为 undefined
});

这里我们有一个传统的node callback形式的getUser,getUserAsync返回一个Promise

  1. new Promise,手动构建Promise

  2. Promise.promisify
    上面示例中的getUserAsync是手动写的,完成的就是Promise.promisify的工作

    api: Promise.promisify(function,receiver) , reviver表示function的this值

generator

MDN : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function*

使用什么的看 http://www.toobug.net/article/learning_es6_generator.html

copy这个示例过来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function* genFn(){
console.log('from GenA, first.');
yield 1;
console.log('from GenA, second.');
var value3 = yield 2;
console.log('from GenA, third.',value3);
return 3;
}

var gen = genFn();

a.next();
// from GenA, first.
// Object {value:1,done:false}

a.next();
// from GenA, second.
// Object {value:2,done:false}

a.next(333);
// from GenA, third.
// 333
// Object {value:3,done:true}

a.next();
// Error: Generator has already finished

执行第一个 next,执行到 yield 1暂停,
执行第二个 next,执行到 yield 2 暂停,
执行第三个 next,传入的 next(333)var value3 = yield 2接受,value3 = 333

放在一起

所谓放在一起,是指 generator yield 的是Promise,在promise完成后继续执行下面的代码,同时把Promise的resolve值传给next

1
2
3
4
// getUserAsync() 返回一个promise
// 而且Promise的resolve值,就是完成态的值,是 一个user对象

var user = yield getUserAsync()

新版的co(co@4.0) 就是用Promise重写的,而且 co(fn)

  • 立即执行,不用以前 co(fn)()
  • 返回Promise

bluebird & co 的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
global.Promise = require('bluebird');
var co = require('co');
var getUserAsync = require('../index').getUserAsync

co(function*() {
console.log(new Date);
var user =
yield getUserAsync('zhang', 'zhang')
console.log(user);
console.log(new Date);
}).catch(function(e) {
console.error(e);
});

可以这样使用

实现也很简单,就是把 generator.next 加到 yield返回的Promise的then上面,把控制流串联起来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function co(genFn) {
var gen = genFn(); // generator

return new Promise(function(reslove, reject) {
next()

function next(lastPromiseVal) { // 上一个promise的val
try {
var ret = gen.next(lastPromiseVal)
}
catch (e) {
reject(e)
}

// yield 返回了一个 ret.value = promise
var promise = ret.value;
if (ret.done) {
reslove(promise); // 用这个
}
else {
promise.then(function(val){
next(val)
});
}
}
});
}

当然没有co考虑那么多。

generator 和 Promise 放在一起,跟C#里面的 async/await/Task 很类似

标记 等待 结果承载
C#.NET async await Task<TResult>
JS function*(){ … } yield Promise

Promise.coroutine

bluebird 中也带了generator的一些东西 https://github.com/petkaantonov/bluebird/blob/master/API.md#generators

跟co差不多,现在的co应该可以拿这个这样实现

  1. module.exports = Promise.coroutine;
  2. Promise.coroutine.addYieldHandler() // 添加yield thunk,array,object 等类型时处理方式