如何在小函数之间传递数据——通过闭包还是通过对象的属性
How should I pass data between small functions - via closures or via properties of an object?
我有一个复杂的业务操作,例如删除一个用户帐户。它包含多个相连的步骤,并且必须跟踪步骤之间的某些状态。写这个action
的更好的方法是什么?
我看到更多像下面这样的functional
方法。
function someAction(someParam, anotherParam, callback) {
async.waterfall([
step1,
step2,
step3,
step4
],callback
);
function step1(p,cb){/**use someParam and anotherParam here via closure*/}
function step2(p,cb){/**...*/}
function step3(p,cb){/**...*/}
function step4(p,cb){/**...*/}
};
someAction('value', 1241, (err)=>{/**...*/});
我不喜欢这种方法的地方是,所有的东西都是在一个函数的范围内定义的(这里是someAction
)。
我发现一个更object-oriented
的方式是更容易读。state和stepX
函数并不是真正私有的——有时它便于测试。
function SomeAction(someParam, anotherParam){
//private state
this._someParam = someParam;
this._anotherParam = anotherParam;
};
SomeAction.prototype._step1 = function(p, cb){
//use this._someParam and this._anotherParam
};
SomeAction.prototype._step2 = function(p, cb){
//use this._someParam and this._anotherParam
};
SomeAction.prototype._step3 = function(p, cb){
//use this._someParam and this._anotherParam
};
SomeAction.prototype._step4 = function(p, cb){
//use this._someParam and this._anotherParam
};
//public api
SomeAction.prototype.execute = function(callback) {
async.waterfall([
this._step1,
this._step2,
this._step3,
this._step4
],callback
)
};
new SomeAction('value', 1241).execute((err)=>{/**...*/})
它们之间有性能差异吗?在Node.js中推荐的方法是什么?这是真的,每次我调用someAction
函数的方法-所有的stepX
函数必须从头开始定义吗?
您可以创建您的阶跃函数的简化版本,并将它们粘贴到瀑布中。
function step1(arg1, arg2, cb){
// Fuction body...
}
// other steps would be defined here...
function step4(arg1, cb){
// fuction body...
}
curried_step1 = step1.bind(undefined, 'junk', 'garb');
// Other steps curried here...
curried_step4 = step4.bind(undefined, 'something');
async.waterfall([
curried_step1,
curried_step2,
curried_step3,
curried_step4
],callback
);
另一种方法是将数据和状态打包到一个对象中(代替真正的单子),并使用该对象传递所需的内容。
你可以使用Promises,它看起来像这样:
var Promise = require('promise');
//** Execute Program **//
main();
/**
* Do your async logic flow here
*/
function main() {
step1()
.then(step2) //Wait for step1 to finish, and pass the response directly to step2
.then(function(res) {
// Do something with res (the return from step2)
// Async execute step3 & step4
var promises = [
step3(),
step4()
];
// Wait for step3 & step4 to finish:
Promise.all([promises[0], promises[1]]).then(function(values) {
console.log(values[0]); //Value from step3
console.log(values[1]); //Value from step4
}).catch(function(e) {
console.log(e); //Reject or thrown errors from steps3 or 4
});
}).catch(function(e) {
console.log(e); //Reject or thrown errors from steps1 or 2
});
}
function step1() {
return new Promise(resolve, reject) {
//some async task here
resolve('step1');
//reject('step1'); //Or trigger a .catch (i.e. this function failed)
});
}
function step2() {
return new Promise(resolve, reject) {
//some async task here
resolve('step2');
//reject('step2'); //Or trigger a .catch (i.e. this function failed)
});
}
function step3() {
return new Promise(resolve, reject) {
//some async task here
resolve('step3');
//reject('step3'); //Or trigger a .catch (i.e. this function failed)
});
}
function step4() {
return new Promise(resolve, reject) {
//some async task here
resolve('step4');
//reject('step4'); //Or trigger a .catch (i.e. this function failed)
});
}
这不是一个完全的答案,但回答了你的间接问题:
问题是我应该如何在这些小函数之间传递数据——通过闭包还是通过对象的属性。
还有第三种方法。如果您熟悉OO设计,那么您可能熟悉命令模式的概念。也就是说,你需要动态地构造一个函数,但这是不可能的,所以你可以用一个方法创建一个对象,然后你可以根据对象的属性自定义。
在函数式编程中,这种设计模式相当于函数工厂模式。基本上就是编写一个函数来生成另一个函数。因此,您希望将someParam
和anotherParam
传递给异步函数,但您希望能够在someAction
函数之外编写该函数。你可以这样做:
function someAction (someParam, anotherParam, callback) {
async.waterfall([
make_step1(someParam,anotherParam),
make_step2(someParam,anotherParam)
/* ... */
],callback
);
}
function make_step1 (someParam, anotherParam) {
return function (p, cb) {
// use someParam and anotherParam here
}
}
function make_step2 (someParam, anotherParam) {
return function (p, cb) {
// use someParam and anotherParam here
}
}
// ...
这消除了您对函数式代码提出的主要异议:您不再需要在someAction()
中定义所有的步骤函数,这使得它看起来更像OO代码。
这仍然会在每次调用someAction()
时创建所有步骤函数的新实例(只是现在从make函数返回)。但是解释器不需要再次编译这些函数。相反,只创建一个新的闭包(将闭包看作是与程序堆栈断开链接的冻结堆栈帧)。
- 附加到原型属性的Do函数没有闭包
- 为Google闭包类定义属性的首选方式是什么
- 使用闭包创建原型中引用的私有属性
- 为什么 Google 闭包编译器会重命名对象的属性名称
- JSHint 错误“对象不支持此属性或方法”用于 javascript 闭包
- 如果全局上下文中的变量是属性,那么为了闭包的目的,如何区分它们
- 谷歌闭包编译器,某些属性永远不会被重命名
- 使用闭包使私有属性成为JavaScript
- 如何在匿名自执行函数中为闭包添加属性
- 在闭包高级编译中获取对象的属性名称
- 闭包编译器未重命名属性和方法(高级编译)
- 获得'未定义'使用闭包工具继承时出现属性错误
- 防止闭包编译器在不使用括号表示法的情况下重命名属性
- 在Angular中,在闭包中引用服务属性/方法最合适的方式是什么?
- 如何在javascript中为闭包编译器注释嵌套对象,并使所有属性都是可选的
- 闭包编译器为什么要重命名外部类型的属性
- 我可以告诉闭包编译器,仅对特定类型停止重命名属性吗?
- CoffeeScript对象属性和闭包
- 谷歌闭包库继承属性
- Javascript闭包属性操作