support Iterable objects, such as Map, Set, String #415
support Iterable objects, such as Map, Set, String #415
Conversation
ce1bb46 to
4596e10
Compare
|
It is better to use |
| if (done) result[count] = itemResult; | ||
| const itemResult = fn(data.next().value, count); | ||
| if (done) { | ||
| if (name === 'Array') result.push(itemResult); |
There was a problem hiding this comment.
FWIW, an object with these types as keys and an appropriate mapping functions as values looks prettier for purpose like this. I suppose, that this piece of code will not be relevant after using common.iter, however just pointing it out for future reference.
There was a problem hiding this comment.
May I ask you a question?
If I replace my const data = items[Symbol.iterator]();
with const data = common.iter(items); I will get almost the same, and I have no need to rewrite code where I use data.next().value.
So, Is it what I am expected to do?
There was a problem hiding this comment.
Yes, I've missconcepted this, you may need here to use a constructor name to add element to result. So it still make sense, AFAIS, to move this conditional statement to a separate function or to make an mapping object described previously, because it is used at least four times in this file, kind of boilerplate code, if I'm not mistaken.
There was a problem hiding this comment.
@mille-nium What do you think about this solution with separate function?
const push = (name, result, value) => {
switch (name) {
case 'Set':
return result.add(value);
case 'Map':
return result.set(value[0], value[1]);
case 'Array':
return result.push(value);
case 'String':
return result += value;
}
return null;
}There was a problem hiding this comment.
I prefer not using switch-case here.
There was a problem hiding this comment.
May I ask you again?
If I separate push function prettier code says that I should change my let result to const result How can I solute this? Can I turn off this option, or what?
There was a problem hiding this comment.
Also, If I give string into object pushValue, I won't concat my string with string += value
If I do something like this, It will work
return;
}
if (name === 'String') result += value;
else push(name, result, value);
count++;
if (count === len) done(null, result);There was a problem hiding this comment.
I wonder, if you could simply use common.Iterator.map() and others methods and then just common.Iterator.collectTo()?
|
|
||
| metatests.test('every', test => { | ||
| metatests.test('every / array', test => { | ||
| const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; |
There was a problem hiding this comment.
I think it can be moved to a separate variable.
There was a problem hiding this comment.
What exactly should I move to separate variable?
const data = [...]
There was a problem hiding this comment.
Yes, const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]. I don't mind different name though.
You can also use |
|
@o-rumiantsev I have one misunderstanding with you. It is said that |
|
Now I have one inaccuracy. If I call method ArrayChain.prototype.fetch = function(fn) {
this.chain.push({ op: 'fetch', fn });
this.execute();
return this;
}; |
|
@SemenchenkoVitaliy @belochub I noticed one interesting detail, I can be wrong so correct me if I am. metatests.test('for chain after fetch', test => {
metasync
.for([1, 2, 3, 4])
.map((item, cb) => process.nextTick(() => cb(null, item * item)))
.filter((item, cb) => process.nextTick(() => cb(null, item > 5)))
.fetch((error, result, resume) => {
test.error(error);
test.strictSame(result, [9, 16]);
process.nextTick(() => resume(null, result));
})
.filter((item, cb) => {
process.nextTick(() => cb(null, item > 10));
})
.map((item, cb) => {
process.nextTick(() => cb(null, --item));
})
.fetch((error, result) => {
test.error(error);
test.strictSame(result, [15]);
test.end();
});
});I will get async functions, but it doesn't work as should, I will get errors. (it is master) |
|
In last commit I have described my problem with |
|
|
||
| metatests.test('every', test => { | ||
| metatests.test('every / array', test => { | ||
| const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; |
| const promise = | ||
| isArray || items.constructor.name === 'String' | ||
| ? data.toArray() | ||
| : data.collectTo(items.constructor); |
There was a problem hiding this comment.
After consulting with @belochub, we agreed that we should return an Iterator object if items is not an Array.
eabbd1d to
1070a5f
Compare
nechaido
left a comment
There was a problem hiding this comment.
Majority of comments apply to every function.
| @@ -231,16 +191,17 @@ const REDUCE_RIGHT_EMPTY_ARR = | |||
| // argument in first iteration | |||
| const reduceRight = (items, fn, done, initial) => { | |||
There was a problem hiding this comment.
reduceRight should probably be implemented on AsyncIterator.
f477971 to
dc722a5
Compare
| @@ -231,16 +191,17 @@ const REDUCE_RIGHT_EMPTY_ARR = | |||
| // argument in first iteration | |||
| const reduceRight = (items, fn, done, initial) => { | |||
| ); | ||
| }); | ||
|
|
||
| // metatests.test('each with error', test => { |
There was a problem hiding this comment.
Why this is commented out?
There was a problem hiding this comment.
Because now each works parallel and this callback callback(eachError); will not cause the stopping of processing other items.
What should I do with this test? rewrite for checking if other elements were processed?
| test.strictSame(result, [15]); | ||
| test.end(); | ||
| }); | ||
| // .filter((item, cb) => process.nextTick(() => cb(null, item < 4))) |
There was a problem hiding this comment.
This problem with fetch after fetch wasn't solved by me. Ask @nechaido.
3c1d416 to
a65fd11
Compare
| .parallel(item => promisify(fn)(item)) | ||
| .then(res => { | ||
| const accepted = res.every(predicateResult => predicateResult); | ||
| done(null, accepted); |
There was a problem hiding this comment.
| done(null, accepted); | |
| done(null, res.every(e => e); |
|
|
||
| class ReverseIterator extends AsyncIterator { | ||
| constructor(base) { | ||
| const newBase = []; |
There was a problem hiding this comment.
This should be done on the first next invocation. base is always AsyncInterotor.
| } | ||
| const isArray = Array.isArray(items); | ||
| asyncIter(items) | ||
| .parallel(item => promisify(fn)(item)) |
There was a problem hiding this comment.
| .parallel(item => promisify(fn)(item)) | |
| .parallel(promisify(fn)) |
| next(); | ||
| const isArray = Array.isArray(items); | ||
| const iter = asyncIter(items) | ||
| .map(item => promisify(fn)(item)) |
There was a problem hiding this comment.
| .map(item => promisify(fn)(item)) | |
| .map(promisify(fn)) |
|
|
||
| metatests.test('with array without element which is searching', test => { | ||
| const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; | ||
| metatests.test('find without element which is searching', test => { |
There was a problem hiding this comment.
| metatests.test('find without element which is searching', test => { | |
| metatests.test('find without the desired element', test => { |
|
|
||
| metasync.reduce( | ||
| arr, | ||
| (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)), |
There was a problem hiding this comment.
| (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)), | |
| test.mustNotCall(), |
| done(null, []); | ||
| // result - <Iterable> | ||
| const map = (items, fn, done = common.emptiness) => { | ||
| if (!items[Symbol.iterator]) { |
There was a problem hiding this comment.
If I understand correctly, Iterable can also contain Symbol.asyncIterator and do not contain Symbol.iterator.
const asyncIterable = {
[Symbol.asyncIterator]() {
return {
i: 0,
next() {
if (this.i < 3) {
return Promise.resolve({ value: this.i++, done: false });
}
return Promise.resolve({ done: true });
}
};
}
};
(async function() {
for await (const i of asyncIterable) {
console.log(i);
}
})();There was a problem hiding this comment.
AFAIU we can omit this check because AsyncIterator constructor will make them.
|
|
||
| if (!items.length) { | ||
| if (done) done(null, []); | ||
| if (!items[Symbol.iterator]) { |
| if (!len) { | ||
| done(null, []); | ||
| const filter = (items, fn, done = common.emptiness) => { | ||
| if (!items[Symbol.iterator]) { |
42ebb93 to
304b2b7
Compare
|
ping @belochub. |
nechaido
left a comment
There was a problem hiding this comment.
Please, split this PR into two commits: one that adds support for Iterables and the one that "updates" tests.
| .parallel(async item => [await promisify(fn)(item), item]) | ||
| .then(res => { | ||
| const filtered = res | ||
| .filter(([predicateResult]) => predicateResult) |
|
|
||
| metasync.asyncMap( | ||
| arr, | ||
| item => item * 2, |
There was a problem hiding this comment.
I'd prefer to leave this test the way it is, to ensure that synchronous functions are still supported.
| metatests.test('every with error', test => { | ||
| const data = [1, 2, 3]; | ||
| const everyErr = new Error('Every error'); | ||
| const everyError = new Error('Every error'); |
There was a problem hiding this comment.
I'd prefer not to rename variables.
| metatests.test('every with empty array', test => | ||
| strictSameResult([], true, test, () => test.end()) | ||
| ); | ||
| metatests.test('every with empty', test => { |
There was a problem hiding this comment.
do we really need to change this?
ee7985b to
4f027ba
Compare
4f027ba to
8cf8ca8
Compare
8cf8ca8 to
d713492
Compare
| // result - <Iterable> | ||
| const map = (items, fn, done = common.emptiness) => { | ||
| const isArray = Array.isArray(items); | ||
| asyncIter(items) |
There was a problem hiding this comment.
I think wrapping everything in AsyncIterator and additionally using util.promisify() adds unnecessary overhead, that can be avoided by just rewriting the original functions with iterators in mind. This also won't require any changes to metasync.AsyncIterator. If we decide to keep it the way it is in this PR we should probably at least benchmark this variant to make sure this doesn't lead to significant performance regressions.
/cc @tshemsedinov
I added support for iterable objects using [Symbol.iterator],
also tests are written