我有一个场景,我希望将2个或更多函数(作为参数)发送到处理函数中,并让该处理函数执行每个传递的函数作为前一个函数的回调函数。
以下是我要编写的函数的一般概念:
function functionChain() {
// MAKE SURE WE HAVE AT LEAST 1 PARAMETER
if ( arguments.length < 1 ) { return; }
// for each parameter, call it (as a function)
for ( var i=0; i<arguments.length; i++) {
if ( typeof arguments[i] === 'function' ) {
call arguments[i];
}
}
}
// example
functionChain( function1, function2, function3 );
...所以在上面的代码中,将连续调用每个函数。
我遇到的问题是如何在前一个函数完成时将每个调用视为回调。
我接近这个的方法是有一个变量(为简单起见,我们只说一个名为functionChainComplete的全局变量),然后等待启动下一个函数 - 当然,我调用的每个函数都会将functionChainComplete设置为true 。所以,像这样:
// set global var for tracking
var functionChainComplete;
function functionChain() {
// MAKE SURE WE HAVE AT LEAST 1 PARAMETER
if ( arguments.length < 1 ) { return; }
// SET GLOBAL VAR TO FALSE
functionChainComplete = true;
// for each parameter, call it (as a function)
for ( var i=0; i<arguments.length; i++) {
if ( typeof arguments[i] === 'function' ) {
if ( functionChainComplete == true ) {
// call the next function and wait for true again
functionChainComplete = false;
call arguments[i];
} else {
// try again in 50 ms (maybe setTimeout)?
}
}
}
}
function1() {
// do something, and when done, reset functionChainComplete
functionChainComplete = true;
}
function2() {
// do something, and when done, reset functionChainComplete
functionChainComplete = true;
}
function3() {
// do something, and when done, reset functionChainComplete
functionChainComplete = true;
}
// example
functionChain( function1, function2, function3 );
正如你所看到的,上面的代码没有解决回调片段,我不知道从这里把它带到哪里 - 我怀疑某种递归函数?我被卡住了。
答案 0 :(得分:1)
假设你有一些函数double
,它接受一个参数,x
和一个回调,k
const double = (x, k) =>
k(x * 2)
double(2, console.log) // 4
double(3, console.log) // 6
现在说我们要连续3次运行它
const double = (x, k) =>
k(x * 2)
const tripleDouble = (x, k) =>
double(x, y =>
double(y, z =>
double(z, k)))
tripleDouble(2, console.log) // 16
tripleDouble(3, console.log) // 24
但当然我们必须对每个延续(y => ...
和z => ...
)进行静态编码。我们如何使用变量(数组)函数来完成这项工作?
const double = (x, k) =>
k(x * 2)
const composek = (...fs) => (x, k) =>
fs.reduce((acc, f) =>
k => acc(x => f(x, k)), k => k(x)) (k)
const foo = composek(double, double, double)
foo(2, console.log) // 16
foo(3, console.log) // 24
这对于一些抽象来说已经成熟,并介绍了我最喜欢的monad,即Continuation Monad。
const Cont = f => ({
runCont: f,
chain: g =>
Cont(k => f(x => g(x).runCont(k)))
})
Cont.of = x => Cont(k => k(x))
const composek = (...fs) => (x, k) =>
fs.reduce((acc,f) =>
acc.chain(x =>
Cont(k => f(x,k))), Cont.of(x)).runCont(k)
const double = (x, k) =>
k(x * 2)
const foo = composek(double, double, double)
foo(2, console.log) // 16
foo(3, console.log) // 24
如果你有自由改变你正在链接的功能,这会更加清理一点 - 在这里,double
有1个参数并返回Cont
而不是作为第二个回调参数
const Cont = f => ({
runCont: f,
chain: g =>
Cont(k => f(x => g(x).runCont(k)))
})
Cont.of = x => Cont(k => k(x))
// simplified
const composek = (...fs) => (x, k) =>
fs.reduce((acc,f) => acc.chain(f), Cont.of(x)).runCont(k)
// simplified
const double = x =>
Cont.of(x * 2)
const foo = composek(double, double, double)
foo(2, console.log) // 16
foo(3, console.log) // 24
当然,如果double
实际上是异步的,那么它将是相同的
// change double to be async; output stays the same
const double = x =>
Cont(k => setTimeout(k, 1000, x * 2))
const foo = composek(double, double, double)
foo(2, console.log) // 16
foo(3, console.log) // 24
答案 1 :(得分:0)
这样的东西? (见评论,但相当不言自明。)
function functionChain() {
var args = arguments;
// MAKE SURE WE HAVE AT LEAST 1 PARAMETER
if ( args.length < 1 ) { return; }
// Start the process
var i = -1;
go();
function go() {
// Pre-increment so we start at 0
++i;
if (i < args.length) {
// We have a next function, do it and continue when we get the callback
args[i](go);
}
}
}
示例:
function functionChain() {
var args = arguments;
// MAKE SURE WE HAVE AT LEAST 1 PARAMETER
if ( args.length < 1 ) { return; }
// Start the process
var i = -1;
go();
function go() {
// Pre-increment so we start at 0
++i;
if (i < args.length) {
// We have a next function, do it and continue when we get the callback
args[i](go);
}
}
}
// Just some functions for an example:
function a(callback) {
console.log("a");
callback();
}
function b(callback) {
console.log("b");
callback();
}
// Note this one is async
function c(callback) {
setTimeout(function() {
console.log("c");
callback();
}, 100);
}
function d(callback) {
console.log("d");
callback();
}
functionChain(a, b, c, d);
也就是说,承诺的原因之一是允许编写可能异步的函数。如果你的函数返回了promises,我们将使用reduce
成语:
function functionChain() {
// Assumes the functions return promises (or at least thenables)
Array.prototype.reduce.call(arguments, function(p, f) {
return p.then(f);
}, Promise.resolve());
}
function functionChain() {
Array.prototype.reduce.call(arguments, function(p, f) {
return p.then(f);
}, Promise.resolve());
}
// Just some functions for an example:
function a(callback) {
return new Promise(function(resolve) {
console.log("a");
resolve();
});
}
function b(callback) {
return new Promise(function(resolve) {
console.log("b");
resolve();
});
}
// Note this one has a delay
function c(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
console.log("c");
resolve();
}, 100);
});
}
function d(callback) {
return new Promise(function(resolve) {
console.log("d");
resolve();
});
}
functionChain(a, b, c, d);
答案 2 :(得分:0)
可以使用nsynjs:
完成此操作
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>
<script>
var wait = function (ctx, ms) {
setTimeout(function () {
console.log('firing timeout');
ctx.resume();
}, ms);
};
wait.nsynjsHasCallback = true;
function synchronousCode() {
function function1() {
console.log('in function1');
wait(nsynjsCtx,1000);
};
function function2() {
console.log('in function2');
wait(nsynjsCtx,1000);
};
function function3() {
console.log('in function3');
wait(nsynjsCtx,1000);
};
function functionChain() {
// MAKE SURE WE HAVE AT LEAST 1 PARAMETER
if ( arguments.length < 1 ) return;
for ( var i=0; i<arguments.length; i++) {
//console.log(i,arguments[i]);
if ( typeof arguments[i] === 'function' ) {
arguments[i]();
};
};
};
functionChain(function1,function2,function3);
}
nsynjs.run(synchronousCode,{},function(){
console.log("Synchronous Code done");
})
</script>
有关更多示例,请参阅https://github.com/amaksr/nsynjs/tree/master/examples。