Reputation: 643
I'm trying to wrap a list of functions over a callback function. Each of the function in the list takes in the value of the callback and returns a modified value. When I try to do this in a straight forward way, it does recursion, and the stack eventually runs out of space, and throws an error.
I tried solving the problem by using a wrapper function that took in a function, wrapped it with another one, and then returned it, and that solved the problem.
Look at the subscribe
function:
class Observable {
constructor() {
this._subscribers = [];
this._operators = [];
}
next(val) {
this._subscribers.forEach(subscriber => {
subscriber(val);
});
}
subscribe(callback) {
if (this._operators.length > 0) {
let ogCallback;
this._operators.forEach((operator, index) => {
ogCallback = callback;
/** ==== call stack full error =====
* callback = (val) => {
* ogCallback(operator(val));
* };
*/
// This works
callback = ((func) => {
const wrapper = (val) => {
func(operator(val));
};
return wrapper;
})(ogCallback);
});
this._operators = [];
}
this._subscribers.push(callback);
}
pipe(operator) {
this._operators.unshift(operator);
return this;
}
}
const observable = new Observable();
observable.pipe(val => val + 2).pipe(val => val * 2).subscribe(val => console.log(val));
observable.next(5);
Why does this happen? They both seem to be the same thing.
Upvotes: 0
Views: 69
Reputation: 147413
I suspect it's from the series of closures created by:
ogCallback = callback;
callback = (val) => {
ogCallback(_function(val));
}
ogCallback and callback are global. After the initial iteration, callback has the value:
(val) => ogCallback(_function(val))
ogCallback has a closure to the global ogCallback, so it's value is whatever it was given from the last iteration, as does callback, potentially causing circular references.
The second example breaks the closure by creating a local variable func in the assigned function expression that is passed the value of ogCallback using an immediately invoked function expression (IIFE).
_functions.forEach((_function, index) => {
ogCallback = callback;
callback = ((func) => {
const wrapper = (val) => {
func(_function(val));
};
return wrapper;
})(ogCallback);
});
Upvotes: 1