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
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
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
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 等类型时处理方式