Home > Article > Web Front-end > Practical and concise implementation of yield in JavaScript_javascript skills
I suddenly had an idea just now. We rarely traverse the iterator directly by going to the next step, so why do we have to implement this next step? Directly implement each, like this, like this in turn, Yeah, one can understand everything, and soon I wrote the first super concise version:
function yieldHost(yieldFunction)
{
return function (processer)
{
var yield = function (result)
{
processer(result)
};
yieldFunction(yield);
};
}
After changing the idea, the code is really concise.
Attach an example first, and then talk about the principle.
First we need a function to enumerate, like this:
function fun(yield)
{
for (var i = 0; i < 100; i )
yield(i);
}
Or like this:
function fun(yield)
{
yield(1);
yield(2);
yield(3);
}
Because the implementation is different from C#, so in the loop There is no need for syntax like yield break or yield continue in the body, just break or continue.
Then for actual application, the yieldHost function can convert the above fun function that meets the requirements into an enumerator:
var enumerator = yieldHost(fun);
This enumerator is actually a function, Like jQuery's each function, it receives a handler function to handle the enumeration:
enumerator(function (item)
{
window.alert(item);
});
Let’s talk about the principle.
For traditional enumerators, we think that the enumerator should return a value every time it is called. This is the next method, but as Chen Zihan said, this requires stopping the function when yielding. Although it can be achieved, it is really troublesome.
But! In fact, I found that most of the time, we use syntax such as foreach to access enumerators. This gives me a very easy way, not to implement the next method, but to implement the each method.
What is the difference between each method and next method? Friends who are familiar with jQuery will know that the each method can actually be regarded as inverting next. Instead of returning an enumeration value, it receives a function and passes the enumeration value as a parameter.
With this move, all problems were solved. We don't need to pause the execution of a function, we just need to inject the logic for processing enumeration values into this function. So in fact, the yieldHost here has completed an inversion work, injecting the function received by the enumerator (that is, window.alert(item)) into the enumeration function (that is, fun). The final execution effect is like this :
function fun(yield)
{
window.alert(1);
window.alert(2);
window.alert(3);
}
So this super simple implementation was born .
With this super simple implementation, the next step is to implement the function of return true for break and return false for continue like jQuery's each method. Only with such a function can we handle infinite sets, or Implement functions such as TakeWhile.
To be honest, my research on JavaScript is not thorough. I only thought of a way to use exception interruption. This is the second version of yieldHost:
function yieldHost(yieldFunction)
{
var exception = Math.random();
return function (processer)
{
try
{
yieldFunction(function (result)
{
if (processer(result))
throw exception;
});
}
catch (e)
{
if (e !== exception)
throw e;
}
};
}
Obviously this isn't perfect, but I really can't think of anything better.
The next step is to implement Select and Where on this basis. It is actually a very simple matter. Here is an implementation of my Select:
function Select(enumerator, selector)
{
return function (fun)
{
enumerator(function (item )
{
return fun(selector(item));
});
}
}
As for how to modify this Select into a continuous version , that is:
enumerator.Select( selector )( processor );
I think this is really not a difficult thing for JavaScript. . . .
It’s just that premature introduction of friendly syntax will make JavaScript very complicated and ugly. So, I leave this to everyone to play with.