Skip to content

Hypothetical patterns for asynchronous IO reads #28

@dtex

Description

@dtex

This is a continuation of conversations had in:

On the call I offered to model some hypothetical API calls to a currently non-existent ECMA-419 asynchronous read API. To be clear, these are examples of I2C reads from the user's perspective. The inner workings of the read implementation are left to the implementor. We're using callbacks since not all target platforms will support promises, and error first call backs can easily be "promisified" in other host environments.

Existing ECMA-419 implementation

Synchronous

read(option[, stop])

Param. Required Range Default
option yes* positive integer, ArrayBuffer, TypedArray
stop no true or false true
  • The number of readable bytes is undefined so option is required
let result = myI2C.read(64);

This pattern makes perfect sense for embedded systems, or anywhere reads are fast enough not to be a problem while blocking.

Possible async patterns

Callback param

readAsync(option[, stop], cb)

Param. Required Range Default
option yes positive integer (number of bytes)
*sto no true or false.
cb yes err first callback
myI2C.readAsync(64, (err, data) => {
  // Do things with the data
});

This seems like the most practical option. By adding a distinct, optional method for asynchronous reads the absence of the method should throw in an unambiguous way. All of the other options listed below could result in implementations that do not throw an error but also do not behave as expected.


Variadic read

read(option[, stop][, cb])

Param. Required Range Default
option yes positive integer (number of bytes)
stop no true or false true
cb no err first callback* null
myI2C.read(64, (err, data) => {
  // Do things with the data
});

I believe that variadic functions make implementation, documentation, and support more difficult. I do not think we should use them here.


Leveraging onReadable

read(option[, stop])

Param. Required Range Default
option yes positive integer (number of bytes)
stop no true or false true

First read returns, when read is complete onReadable fires. This requires user code to manage state:

  • Does each read trigger a read or process the results of a read?
  • What register address was last read and which read request does this onReadable correspond to?
const myI2C = new device.I2C({
			...device.I2C.default,
			onReadable: () => {
     let data = myI2C.read(64);
     if data === null return;
     // do something with the data
			}
 });

let data = myI2C.read(64); // expets null

Because of the burden put on the user, I do not think this is a good pattern.

Adding an onread property

read(option[, stop])

Param. Required Range Default
option yes positive integer (number of bytes)
stop no true or false true

Read only triggers, when read is complete onReadable fires. This requires user code to manage state:

  • Does each read trigger a read or process the results of a read?
  • What register address was last read and which read request does this onReadable correspond to?
const myI2C = new device.I2C({
			...device.I2C.default,
			onReadable: () => {
     this.read(64);
   },
   onRead: (data) => {
     if data === null return;
     // do something with the data
			}
 });

let data = myI2C.read(64); // expets null

Because of the burden put on the user, I do not think this is a good pattern

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions