Чтобы быть действительным asyncIterator
, ваша функция test
должна возвращать объект методом next
, который возвращает обещание результирующего объекта со свойствами value
и done
. (Технически, value
является необязательным, если его значение будет undefined
, а done
является необязательным, если его значение будет false
, но ...)
Вы можете сделать это несколькими способами:
- Полностью вручную (неудобно, особенно если вам нужен правильный прототип)
- Половина вручную (немного менее неловко, но все еще неловко, чтобы получить правильный прототип)
- Использование функции асинхронного генератора (самое простое)
Вы можете сделать это полностью вручную (это не попытается получить правильный прототип):
function test() {
let i = -1;
return {
next() {
++i;
if (i >= 10) {
return Promise.resolve({
value: undefined,
done: true
});
}
return Promise.resolve({
value: i > 5 ? `Greater than 5: (${i})` : `Less than 5: (${i})`,
done: false
});
}
};
}
let a = {
[Symbol.asyncIterator]: test
};
async function main() {
for await (let x of a) {
console.log(x)
}
}
main()
.then(r => console.log(r))
.catch(err => console.log(err))
Вы можете сделать это наполовину вручную, написав функцию, которая возвращает объект с помощью метода async
next
(все еще не пытается получить правильный прототип):
function test() {
let i = -1;
return {
async next() {
++i;
if (i >= 10) {
return {
value: undefined,
done: true
};
}
return {
value: i > 5 ? `Greater than 5: (${i})` : `Less than 5: (${i})`,
done: false
};
}
};
}
let a = {
[Symbol.asyncIterator]: test
};
async function main() {
for await (let x of a) {
console.log(x)
}
}
main()
.then(r => console.log(r))
.catch(err => console.log(err))
Или вы можете просто использовать функцию генератора async
(проще всего, и автоматически получает правильный прототип):
async function* test() {
for (let i = 0; i < 10; ++i) {
yield i > 5 ? `Greater than 5: (${i})` : `Less than 5: (${i})`;
}
}
let a = {
[Symbol.asyncIterator]: test
};
async function main() {
for await (let x of a) {
console.log(x)
}
}
main()
.then(r => console.log(r))
.catch(err => console.log(err))
О прототипах: все асинхронные итераторы, которые вы получаете из самой среды выполнения JavaScript, наследуют от прототипа, который обеспечивает основную возможность обеспечения итератора также итерируемого (при наличии Symbol.iterator
функции, возвращающей this
). Для этого прототипа нет общедоступного идентификатора или свойства, вам нужно прыгнуть через обручи, чтобы получить его:
const asyncIteratorPrototype =
Object.getPrototypeOf(
Object.getPrototypeOf(
async function*(){}.prototype
)
);
Тогда вы использовали бы это в качестве прототипа объекта с методом next
, который вы возвращаете:
return Object.assign(Object.create(asyncIteratorPrototype), {
next() {
// ...
}
});