Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

State of the spec ? + useful example #10

Open
lifaon74 opened this issue Nov 10, 2020 · 3 comments
Open

State of the spec ? + useful example #10

lifaon74 opened this issue Nov 10, 2020 · 3 comments

Comments

@lifaon74
Copy link

lifaon74 commented Nov 10, 2020

Hi, I would know where was this project ? I'm very interested in this specs as it would solve many problems js developers face with generator used as "data receiver" instead of "data emiter" (or both).

I may share another very practical use case of function.sent:

export interface IGetPaginatedDataOptions {
  signal?: AbortSignal;
}

export class Pagination<GData> {
  getPaginatedData(page: IPageInfo, options?: IGetPaginatedDataOptions): Promise<IPaginatedData<GData>> {
    return fetch('some url', options).then(_ => _.json());
  }

  /**
   * Creates an async iterator over the list of pages
   */
  async* pageIterator({ pageIndex = 0, itemsPerPage = 10 }: Partial<IPageInfo> = {}): AsyncGenerator<IPaginatedData<GData>, any, any> {
    const page: IPageInfo = { pageIndex, itemsPerPage };
    let result: IPaginatedData<GData>;
    do {
      result = await this.getPaginatedData(page, function.sent); // note just here the usage of funtion.sent
      yield result;
      page.pageIndex++;
    } while (result.pageCount > page.pageIndex);
  }
}

const pagination = new Pagination().pageIterator();
const controller = new AbortController();
setTimeout(() => controller.abort('timeout'), 5000);
const page = await pagination.next(controller);

It could be extremely useful for AsyncIterators ! Hope it's not dead ?

@Pyrolistical
Copy link

why couldn't you just pass that into the iterator?

export interface IGetPaginatedDataOptions {
  signal?: AbortSignal;
}

export class Pagination<GData> {
  getPaginatedData(page: IPageInfo, options?: IGetPaginatedDataOptions): Promise<IPaginatedData<GData>> {
    return fetch('some url', options).then(_ => _.json());
  }

  /**
   * Creates an async iterator over the list of pages
   */
  async* pageIterator(controller, { pageIndex = 0, itemsPerPage = 10 }: Partial<IPageInfo> = {}): AsyncGenerator<IPaginatedData<GData>, any, any> {
    const page: IPageInfo = { pageIndex, itemsPerPage };
    let result: IPaginatedData<GData>;
    do {
      result = await this.getPaginatedData(page, controller);
      yield result;
      page.pageIndex++;
    } while (result.pageCount > page.pageIndex);
  }
}

const controller = new AbortController();
const pagination = new Pagination().pageIterator(controller);
setTimeout(() => controller.abort('timeout'), 5000);
const page = await pagination.next();

@lifaon74
Copy link
Author

In my example, the purpose is to cancel individually the request, not the whole iteration

@hax
Copy link
Member

hax commented May 25, 2022

@lifaon74 Thank you for the wonderful example.

I'm planning update the proposal in next TC39 meeting.

My idea is moving from function.sent meta property to receive parameter. So your example would become:

...
  /**
   * Creates an async iterator over the list of pages
   */
  async* pageIterator({ pageIndex = 0, itemsPerPage = 10 } = {}) 
      receive (signal: AbortSignal) {
    const page = { pageIndex, itemsPerPage };
    let result: IPaginatedData<GData>;
    do {
      result = await this.getPaginatedData(page, {signal});
      yield result;
      page.pageIndex++;
    } while (result.pageCount > page.pageIndex);
  }
...
const page = await pagination.next(controller.signal) // only send signal to avoid exposing too many power (like .abort())

I think this example also show some merits of receive param than function.sent.

First, the information is on the method signature now. In the function.sent version, we can't see the generator could have extra option. We need to go through the method body and check the existence of function.sent or x = yield pattern.

Second, even we see await this.getPaginatedData(page, function.sent), it's unclear what function.sent is for, so we need to follow getPaginatedData definition and guess what function.sent give us. On the other side, receive parameter is just a parameter, so it could has a descriptive name and type annotation directly (or even parameter decorators in the future).

Third, it also allow TS infer the return type of the generator function so I removed the wordy return type (See #13 ).

I hope this direction could be approved by the committee, and help your use cases :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants