FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

readline: add support for async iteration by prog1dev · Pull Request #18904 · nodejs/node · GitHub

/ node Public

readline: add support for async iteration - #18904

Closed
prog1dev wants to merge 2 commits into
nodejs:masterfrom
prog1dev:readline/add_support_for_async_iteration
Closed

readline: add support for async iteration#18904
prog1dev wants to merge 2 commits into
nodejs:masterfrom
prog1dev:readline/add_support_for_async_iteration

Conversation

prog1dev commented Feb 21, 2018
edited
Loading

Copy link
Copy Markdown
Contributor

Sync readline API with for-await-of support in readable streams

Resolves #18603

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

readline, stream, doc, test

@vsemozhetbyt @mcollina

nodejs-github-bot added the readline Issues and PRs related to the built-in readline module. label Feb 21, 2018

mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Good work, LGTM

Copy link
Copy Markdown
Member

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Shouldn't this really be writeFileSync() to avoid any potential race conditions?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Can't this instead be moved to the common.mustCall() callback?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

It can be removed entirely. Test files do not need to clean up the temp directory. Tests that use the temp directory clean it up themselves at the start of the test with tmpdir.refresh().

prog1dev Feb 22, 2018
edited
Loading

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@Trott Is that worth to also clean up current fs tests in separate pr? example

targos added the semver-minor PRs that contain new features and should be released in the next minor version. label Feb 21, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I think it would be nice to check how many iterations of the loop there were

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

A nit: destruction?

vsemozhetbyt Feb 21, 2018
edited
Loading

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

A nit: arrow function?

vsemozhetbyt commented Feb 21, 2018
edited
Loading

Copy link
Copy Markdown
Contributor

Just a tiny doubt: the readline module works with strings only and users may get used to this (line in the listener argument is always a string). Should we demand from a user to use readable.setEncoding('utf8'); here? Maybe we can do this internally? BTW, the test does not use this call.

prog1dev commented Feb 22, 2018
edited
Loading

Copy link
Copy Markdown
Contributor Author

@vsemozhetbyt By demand you mean explicitly mention this in documentation?
I can set encoding in Interface.prototype[Symbol.asyncIterator] if you think this is a good thing to do.

Comment thread lib/readline.js Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

nit: in a project it may not be clear what Interface is

devsnek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

lgtm with nits

Copy link
Copy Markdown
Contributor

@prog1dev Yes, documented advice.
Let us see what others think about it, I may be wrong.

vsemozhetbyt commented Feb 23, 2018
edited
Loading

Copy link
Copy Markdown
Contributor

@prog1dev I've compiled the branch and tested the slightly edited doc example code on Windows 7 x64.

  1. readable.setEncoding('utf8'); seems do not affect the behavior (it is the same with it or without it).
  2. It seems we have only one iteration with many lines glued together:
'use strict';

const readline = require('readline');
const fs = require('fs');

async function processLineByLine(readable) {
  // readable.setEncoding('utf8');
  const rli = readline.createInterface({
    input: readable,
    crlfDelay: Infinity
  });

  let i = 0;

  for await (const line of rli) {
    console.log(`Line ${++i}: ${line}`);
  }
}

processLineByLine(fs.createReadStream(__filename)).catch(console.error);
(node:3148) ExperimentalWarning: Interface[Symbol.asyncIterator] is an experimental feature. This feature could change at any time
Line 1: 'use strict';

const readline = require('readline');
const fs = require('fs');

async function processLineByLine(readable) {
  // readable.setEncoding('utf8');
  const rli = readline.createInterface({
    input: readable,
    crlfDelay: Infinity
  });

  let i = 0;

  for await (const line of rli) {
    console.log(`Line ${i}: ${line}`);
  }
}

processLineByLine(fs.createReadStream(__filename)).catch(console.error);

Dear reviewers, please chime in.

TimothyGu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

As in @vsemozhetbyt’s example, the added method doesn’t work. readline emits 'line' events that needed to be listened for, not 'data' as is the case for readable streams. As such, the general stream async iterator cannot be used for readline.

The PR just gets an async iterator of the input stream. That completely skips the readline mechanism, and as such does not work.

prog1dev commented Feb 23, 2018
edited
Loading

Copy link
Copy Markdown
Contributor Author

@mcollina Looks like no matter how much lines file has there is only one iteration of for-await-of. Here is code example:

async function print(readable) {
  readable.setEncoding('utf8');
  let data = '';
  let iterations = 0;
  for await (const k of readable) {
    data += k;
    iterations++;
  }
  console.log(data);
  console.log(iterations);
}

print(fs.createReadStream('file')).catch(console.log);

Is this behaviour intentional? Its different for readable streams in object mode
I guess its because fs.createReadStream('file').read() returns null

vsemozhetbyt added the experimental Issues and PRs related to experimental features. label Feb 23, 2018

Copy link
Copy Markdown
Contributor

It seems the longing readline to be more like streams has some backing, for example #16178.

TBH, when I started to learn Node.js, using readline for a file processing seemed to me a bit hacky, with all the terminal abundant API to be ignored. And it becomes more awkward with things like crlfDelay: Infinity.

But this is a pretty basic tool for text file processing to be outsourced to more handy userland modules. And this async API would be a big step towards making readline more usable outside the CLI domain till we will have something more concise.

mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

-1 based on @vsemozhetbyt exmaple.

Copy link
Copy Markdown
Member

Is this behaviour intentional? Its different for readable streams in object mode

I'm pretty sure this is is because of internal buffering. You should try reading a different file. This is an experimental feature, and I would be surprise if it does not have bugs. Feel free to send PRs to fix those.

BridgeAR commented Mar 2, 2018

Copy link
Copy Markdown
Member

Ping @prog1dev

prog1dev commented Mar 3, 2018
edited
Loading

Copy link
Copy Markdown
Contributor Author

@BridgeAR Im working on this in my spare time

prog1dev force-pushed the readline/add_support_for_async_iteration branch from e3532d8 to 3468ed9 Compare March 12, 2018 20:20
prog1dev force-pushed the readline/add_support_for_async_iteration branch from 716e6f1 to 2f5c558 Compare May 5, 2018 17:21

Copy link
Copy Markdown
Contributor

Comment thread lib/readline.js
return null;

return this._buffer.shift();
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Can we make this function private?

prog1dev May 20, 2018
edited
Loading

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

You mean to rename it to _read?

Comment thread lib/readline.js

this._enableBuffer = true;
this.close();
this.input.setEncoding('utf8');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

It's definitely not super friendly when a module like readline changes stream settings, especially when we only do it with async iteration. We should add this feature without it.

Comment thread lib/readline.js
emitExperimentalWarning('readline Interface[Symbol.asyncIterator]');

this._enableBuffer = true;
this.close();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

We definitely should not close the readline interface when we start iterating. This will emit events like 'close' that can be very much misleading to users.

prog1dev May 20, 2018
edited
Loading

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

In order for it to work stream must be in paused mode so I can get data with stream.read() calls. So instead of closing I guess I can pause it with this.input.pause()

Comment thread lib/readline.js
Interface.prototype[Symbol.asyncIterator] = function() {
emitExperimentalWarning('readline Interface[Symbol.asyncIterator]');

this._enableBuffer = true;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I don't see this ever getting restored after the completion of iteration, and I feel like it should be. Correct me if I'm wrong :)

Copy link
Copy Markdown
Member

There is still a lot of logic shared between ReadableAsyncIterator and ReadlineAsyncIterator, like the entire

      this[kLastResolve] = null;
      this[kLastReject] = null;
      this[kError] = null;
      this[kEnded] = false;
      this[kLastPromise] = null;

chunk in the constructor, and also the this[kHandlePromise] function. BaseAsyncIterator could definitely have some more common code.

Comment thread lib/readline.js
this.isCompletionEnabled = true;
this._sawKeyPress = false;
this._previousKey = null;
this._enableBuffer = false;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Can you please add a comment on what this does? Also, I would prefer if this was a Symbol instead.

mcollina commented May 7, 2018

Copy link
Copy Markdown
Member

Let me toy with an idea.. how about we implement this on top of a PassThrough instead?
Basically we listen to the 'line' event and we write to a PassThrough with objectMode: true. Then, we use that to create the AsyncIterator. It seems we are doubling some streams machinery here.

jasnell commented Oct 17, 2018

Copy link
Copy Markdown
Member

What's the status on this?

Copy link
Copy Markdown
Contributor Author

@jasnell Stalled. Maybe later this week I can check this PassThrough idea. Also at that time I could not find an easy way to solve this #18904 (comment) issue

Copy link
Copy Markdown
Member

@prog1dev Would it be okay with you if I were to take over this PR?

Copy link
Copy Markdown
Contributor Author

@TimothyGu Sure go on

TimothyGu added the wip Issues and PRs that are still a work in progress. label Oct 25, 2018

Copy link
Copy Markdown
Member

New PR opened at #23916.

TimothyGu added a commit to TimothyGu/node that referenced this pull request Nov 20, 2018
Co-authored-by: Ivan Filenko <ivan.filenko@protonmail.com>
Fixes: nodejs#18603
Refs: nodejs#18904
Trott pushed a commit to Trott/io.js that referenced this pull request Nov 20, 2018
Co-authored-by: Ivan Filenko <ivan.filenko@protonmail.com>
Fixes: nodejs#18603
Refs: nodejs#18904
PR-URL: nodejs#23916
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
prog1dev closed this Nov 20, 2018
prog1dev deleted the readline/add_support_for_async_iteration branch November 20, 2018 23:46
targos pushed a commit that referenced this pull request Nov 21, 2018
Co-authored-by: Ivan Filenko <ivan.filenko@protonmail.com>
Fixes: #18603
Refs: #18904
PR-URL: #23916
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
rvagg pushed a commit that referenced this pull request Nov 28, 2018
Co-authored-by: Ivan Filenko <ivan.filenko@protonmail.com>
Fixes: #18603
Refs: #18904
PR-URL: #23916
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
refack pushed a commit to refack/node that referenced this pull request Jan 14, 2019
Co-authored-by: Ivan Filenko <ivan.filenko@protonmail.com>
Fixes: nodejs#18603
Refs: nodejs#18904
PR-URL: nodejs#23916
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
BethGriggs pushed a commit that referenced this pull request Apr 17, 2019
Co-authored-by: Ivan Filenko <ivan.filenko@protonmail.com>
Fixes: #18603
Refs: #18904
PR-URL: #23916
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
BethGriggs pushed a commit that referenced this pull request Apr 28, 2019
Co-authored-by: Ivan Filenko <ivan.filenko@protonmail.com>
Fixes: #18603
Refs: #18904
PR-URL: #23916
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
MylesBorins pushed a commit that referenced this pull request May 16, 2019
Co-authored-by: Ivan Filenko <ivan.filenko@protonmail.com>
Fixes: #18603
Refs: #18904
PR-URL: #23916
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

experimental Issues and PRs related to experimental features. readline Issues and PRs related to the built-in readline module. semver-minor PRs that contain new features and should be released in the next minor version. stalled Issues and PRs that are stalled. wip Issues and PRs that are still a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.


Back | FazBrowse Home | New Git URL