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)
})
没有异常抛出,开发者可能会忽略掉这个异常
      14 回复
    
    
@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 系统。
都说bluebird性能好, 而且很多库可选依赖Promise时也建议bluebird.
bluebird出现的晚, 基本功能部分遵循标准, 所以才敢在教程里写 var Promise = require('bluebird');
出来啦 https://github.com/thunks/thunks/issues/5 :
thunks 的作用域和异常处理设计
我认为,thunks 的作用域和异常处理设计是完美的,如果你发现不完美,那一定是
bug,请告知我来修复。