Closed jzapletal95 closed 1 year ago
Hi @jzapletal95,
You're right that, currently, JavaScript objects aren't enumerable, in either normal or asynchronous modes. There are exceptions – arrays implement IList
, and soon most other JavaScript objects will implement IDictionary<string, object>
– but there's no mapping of JavaScript's iteration protocols to IEnumerable
/IAsyncEnumerable
.
However, nothing stops you from building such support yourself. For example, you could define extension methods that convert script objects to enumerables. Here's a class that provides an example:
public static class ScriptObjectExtensions {
public static void Initialize(ScriptEngine engine) {
engine.Execute(@"
Object.prototype.getIterator = function () { return this[Symbol.iterator]?.call(this); }
Object.prototype.getAsyncIterator = function () { return this[Symbol.asyncIterator]?.call(this); }
");
}
public static IEnumerable<object> ToEnumerable(this ScriptObject iterable) {
if (iterable.InvokeMethod("getIterator") is ScriptObject iterator) {
while (iterator.InvokeMethod("next") is ScriptObject result && !result["done"].Equals(true)) {
yield return result["value"];
}
}
}
public static async IAsyncEnumerable<object> ToAsyncEnumerable(this ScriptObject asyncIterable) {
if (asyncIterable.InvokeMethod("getAsyncIterator") is ScriptObject asyncIterator) {
while (await asyncIterator.InvokeMethod("next").ToTask() is ScriptObject result && !result["done"].Equals(true)) {
yield return result["value"];
}
}
}
}
And here's how you might use it:
using var engine = new V8ScriptEngine();
ScriptObjectExtensions.Initialize(engine);
engine.Script.delay = new Func<int, object>(ms => Task.Delay(ms).ToPromise());
engine.Execute(@"
async function* foo() {
await delay(1000); yield 'This ';
await delay(1000); yield 'is ';
await delay(1000); yield 'not ';
await delay(1000); yield 'a ';
await delay(1000); yield 'drill!';
}
");
var asyncIterable = (ScriptObject)engine.Script.foo();
await foreach (var text in asyncIterable.ToAsyncEnumerable()) {
Console.Write(text);
}
Console.WriteLine();
Please let us know if you have additional thoughts or findings.
Thanks!
Thank you for your advice and for releasing a new version. Everything works good.
Hi guys, I am using ClearScript (v7.3.7) in my project. Currently i'm struggling with transfer of AsyncIterable from V8 to C#. You have implemented automatic marshalling in oposite way (AsyncEnumerable -> AsyncIterable) but i cannot find the way how to pass it. Any ideas?