Thunks 是个好东东。
不过我是个Q的重度使用者,今天对比了一下Thunks和Q,提点建议。
所有thunks正确返回时,输出风格不好
基于promise的代码
var Q = require('q'),
fs = require('fs'),
qsize = Q.denodeify(fs.stat);
qsize('package.json').then(function(){
var promises = [];
promises.push('plain value');
promises.push(qsize('thunk.js'));
promises.push(qsize('package.json'));
promises.push('hello world');
return promises;
}).then(Q.all)
.then(console.log)
.fail(console.log)
.done();
输出
//一维数组
[ 'plain value',
{ dev: 0,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
ino: 0,
size: 358,
atime: Mon Nov 24 2014 10:06:57 GMT+0800 (China Standard Time),
mtime: Mon Nov 24 2014 10:44:11 GMT+0800 (China Standard Time),
ctime: Mon Nov 24 2014 10:06:57 GMT+0800 (China Standard Time) },
{ dev: 0,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
ino: 0,
size: 70,
atime: Mon Nov 24 2014 10:01:35 GMT+0800 (China Standard Time),
mtime: Mon Nov 24 2014 10:35:46 GMT+0800 (China Standard Time),
ctime: Mon Nov 24 2014 10:01:35 GMT+0800 (China Standard Time) },
'hello world' ]
基于Thunks的代码
var Thunks = require('thunks')(),
fs = require('fs');
var size = Thunks.thunkify(fs.stat);
size('package.json')(function(err,res){
var thunks = [];
thunks.push('plain value');
thunks.push(size('thunk.js'));
thunks.push(size('package.json'));
thunks.push('hello world');
return thunks;
})(Thunks.all)
(function(err,res){
console.log(res)
})
输出
//没理解包一个数组在外面的意图
[ null,
[ 'plain value',
{ dev: 0,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
ino: 0,
size: 364,
atime: Mon Nov 24 2014 10:06:57 GMT+0800 (China Standard Time),
mtime: Mon Nov 24 2014 10:53:55 GMT+0800 (China Standard Time),
ctime: Mon Nov 24 2014 10:06:57 GMT+0800 (China Standard Time) },
{ dev: 0,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
ino: 0,
size: 70,
atime: Mon Nov 24 2014 10:01:35 GMT+0800 (China Standard Time),
mtime: Mon Nov 24 2014 10:35:46 GMT+0800 (China Standard Time),
ctime: Mon Nov 24 2014 10:01:35 GMT+0800 (China Standard Time) },
'hello world' ] ]
缺少allSettled。当某个thunk出现错误时,不好处理
基于promise的代码
var Q = require('q'),
fs = require('fs'),
qsize = Q.denodeify(fs.stat);
qsize('package.json').then(function(){
var promises = [];
promises.push('plain value');
promises.push(qsize('notexisted.js'));
promises.push(qsize('package.json'));
promises.push('hello world');
return promises;
}).then(Q.allSettled)
.then(console.log)
.fail(console.log)
.done();
输出
[ { state: 'fulfilled', value: 'plain value' },
{ state: 'rejected',
reason:
{ [Error: ENOENT, stat 'D:\AA\NodeSchool\Thunk\notexisted.js']
errno: 34,
code: 'ENOENT',
path: 'D:\\AA\\NodeSchool\\Thunk\\notexisted.js' } },
{ state: 'fulfilled',
value:
{ dev: 0,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
ino: 0,
size: 70,
atime: Mon Nov 24 2014 10:01:35 GMT+0800 (China Standard Time),
mtime: Mon Nov 24 2014 10:35:46 GMT+0800 (China Standard Time),
ctime: Mon Nov 24 2014 10:01:35 GMT+0800 (China Standard Time) } },
{ state: 'fulfilled', value: 'hello world' } ]
基于Thunks的代码
var Thunks = require('thunks')(),
fs = require('fs');
var size = Thunks.thunkify(fs.stat);
size('package.json')(function(err,res){
var thunks = [];
thunks.push('plain value');
thunks.push(size('notexisted.js'));
thunks.push(size('package.json'));
thunks.push('hello world');
return thunks;
})(Thunks.all)
(function(err,res){
console.log(err)
})
输出
{ [Error: ENOENT, stat 'D:\AA\NodeSchool\Thunk\notexisted.js']
errno: 34,
code: 'ENOENT',
path: 'D:\\AA\\NodeSchool\\Thunk\\notexisted.js' }
thunks链错误处理的思路比较独特
promise代码(promise链)
var Q = require('q'),
fs = require('fs'),
qsize = Q.denodeify(fs.stat);
qsize('package.json')
.then(function(data){
console.log(data);
return qsize('thunk.js')
})
.then(function(data){
console.log(data)
return qsize('notexsited.js')
})
.then(function(data){
console.log(data)
return qsize('package.json')
})
.then(function(data){
console.log(data)
})
.fail(function(err){
console.log(err);
})
输出
//某个节点发生错误时,promise链停止运行。
//可以通过fail统一处理错误 使用方便。比较符合try catch模式的写法
{ dev: 0,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
ino: 0,
size: 70,
atime: Mon Nov 24 2014 10:01:35 GMT+0800 (China Standard Time),
mtime: Mon Nov 24 2014 10:35:46 GMT+0800 (China Standard Time),
ctime: Mon Nov 24 2014 10:01:35 GMT+0800 (China Standard Time) }
{ dev: 0,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
ino: 0,
size: 394,
atime: Mon Nov 24 2014 10:06:57 GMT+0800 (China Standard Time),
mtime: Mon Nov 24 2014 11:11:30 GMT+0800 (China Standard Time),
ctime: Mon Nov 24 2014 10:06:57 GMT+0800 (China Standard Time) }
{ [Error: ENOENT, stat 'D:\AA\NodeSchool\Thunk\notexsited.js']
errno: 34,
code: 'ENOENT',
path: 'D:\\AA\\NodeSchool\\Thunk\\notexsited.js' }
Thunks代码(thunks链)
var Thunks = require('thunks'),
fs = require('fs');
var Thunk = Thunks({
onerror:function(error){console.log(error)}
});
var size = Thunk.thunkify(fs.stat);
size('package.json')(function(err,res){
console.log(err,res);
return size('thunk.js');
})(function(err,res){
console.log(err,res);
return size('notexsited.js')
})(function(err,res){
console.log(err,res)
return size('package.json');
})(function(err,res){
console.log(err,res)
})
输出
//不太符合try catch模式的写法
null { dev: 0,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
ino: 0,
size: 70,
atime: Mon Nov 24 2014 10:01:35 GMT+0800 (China Standard Time),
mtime: Mon Nov 24 2014 10:35:46 GMT+0800 (China Standard Time),
ctime: Mon Nov 24 2014 10:01:35 GMT+0800 (China Standard Time) }
null { dev: 0,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
ino: 0,
size: 464,
atime: Mon Nov 24 2014 10:06:57 GMT+0800 (China Standard Time),
mtime: Mon Nov 24 2014 11:30:39 GMT+0800 (China Standard Time),
ctime: Mon Nov 24 2014 10:06:57 GMT+0800 (China Standard Time) }
{ [Error: ENOENT, stat 'D:\AA\NodeSchool\Thunk\notexsited.js']
errno: 34,
code: 'ENOENT',
path: 'D:\\AA\\NodeSchool\\Thunk\\notexsited.js' }
当没有注册错误处理时,Thunks不会抛出错误
promise代码
var Q = require('q'),
fs = require('fs'),
qsize = Q.denodeify(fs.stat);
qsize('package.json')
.then(function(data){
console.log(data);
return qsize('thunk.js')
})
.then(function(data){
console.log(data)
return qsize('notexsited.js')
})
.then(function(data){
console.log(data)
return qsize('package.json')
})
.then(function(data){
console.log(data)
})
.done();
输出
程序抛出exception,提醒开发者有错误没有处理
Thunks代码
var Thunks = require('thunks'),
fs = require('fs');
var Thunk = Thunks();
var size = Thunk.thunkify(fs.stat);
size('package.json')(function(err,res){
console.log(err,res);
return size('thunk.js');
})(function(err,res){
return size('notexsited.js')
})(function(err,res){
console.log(err,res)
return size('package.json');
})(function(err,res){
console.log(err,res)
})
没有异常抛出,开发者可能会忽略掉这个异常
@eeandrew 你的写法有问题~,正确写法如下:
size('package.json')(function(err,res){
return Thunks.all(['plain value', size('thunk.js'), size('package.json'), 'hello world']);
})(function(err,res){
console.log(res)
})
关于作用域和异常处理的设计,待会儿贴个文章出来,简而言之,比promise高明,用 thunks 的话无需再用 node.js 的 domain 系统。
楼主我也想用Q,有没有中文资料,关于Q api用法的。? 我现在用的bluebird 也是一知半解。另,能不能说说Q和bluebird哪个好?
bluebird很好呀,二和一
都说bluebird性能好, 而且很多库可选依赖Promise时也建议bluebird.
bluebird出现的晚, 基本功能部分遵循标准, 所以才敢在教程里写 var Promise = require('bluebird');
@eeandrew 谢楼主,我好好看看。
@colder bluebird还有这些故事,涨见识了。
@i5ting 二合一,此话怎讲?
出来啦 https://github.com/thunks/thunks/issues/5 :
thunks 的作用域和异常处理设计
我认为,thunks 的作用域和异常处理设计是完美的,如果你发现不完美,那一定是
bug
,请告知我来修复。
Q 有内存泄露问题(几个月前测试的),速度也慢,如果用 promise,还是建议用 bluebird
另,thenjs 的 benchmark 原来是有 Q 的,因为它老是垫底,加上后来发现的泄露问题,就去除了(请不要叫我 Q 黑)
@zensh 我去 重头学习
@winky 是这样的,它支持generator和promise/A+