Skip to content

fs: initial experimental promisified API

Rodrigo Muino Tomonari requested to merge github/fork/jasnell/async-fs into master

Introduces an experimental promises API for the fs module. The API is accessible via fs.async, e.g.

This is intended to land as Experimental.

const { async:fs } = require('fs');

fs.access('.')
  .then(console.log)
  .catch(console.error);

Most fs functions are supported. There are some variations from the base fs module (for instance, fs.async.realpath() uses the faster libuv realpath implementation rather than the slower js implementation.

This does not yet include documentation updates.

Semver-major because this makes substantive changes to error handling in the existing fs module.

Benchmarks are included. For instance,

access

james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-access.js
fs/promises-access.js method="legacy" n=200000: 280,078.9048933864
fs/promises-access.js method="promisify" n=200000: 69,310.04884236863
fs/promises-access.js method="promise" n=200000: 240,928.00098102028
james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-access.js
fs/promises-access.js method="legacy" n=200000: 236,062.80841465757
fs/promises-access.js method="promisify" n=200000: 82,258.05538216804
fs/promises-access.js method="promise" n=200000: 192,776.68164314007
james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-access.js
fs/promises-access.js method="legacy" n=200000: 112,929.07886994253
fs/promises-access.js method="promisify" n=200000: 136,272.83764802708
fs/promises-access.js method="promise" n=200000: 169,612.60194223037
james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-access.js
fs/promises-access.js method="legacy" n=200000: 163,294.66290369138
fs/promises-access.js method="promisify" n=200000: 119,130.69228308211
fs/promises-access.js method="promise" n=200000: 185,855.53426089959

copyFile

james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-copyfile.js
fs/promises-copyfile.js method="legacy" n=20000: 282,755.1240812897
fs/promises-copyfile.js method="promisify" n=20000: 166,754.91197646034
fs/promises-copyfile.js method="promise" n=20000: 101,068.59267154362
james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-copyfile.js
fs/promises-copyfile.js method="legacy" n=20000: 264,452.6619289267
fs/promises-copyfile.js method="promisify" n=20000: 84,065.33716046945
fs/promises-copyfile.js method="promise" n=20000: 100,486.89215315646
james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-copyfile.js
fs/promises-copyfile.js method="legacy" n=20000: 270,616.2934281645
fs/promises-copyfile.js method="promisify" n=20000: 156,420.93141688287
fs/promises-copyfile.js method="promise" n=20000: 103,760.93116221747
james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-copyfile.js
fs/promises-copyfile.js method="legacy" n=20000: 251,781.945806882
fs/promises-copyfile.js method="promisify" n=20000: 118,330.0739314469
fs/promises-copyfile.js method="promise" n=20000: 266,315.20161791815
james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-copyfile.js
fs/promises-copyfile.js method="legacy" n=20000: 106,352.46687950206
fs/promises-copyfile.js method="promisify" n=20000: 120,297.63535689937
fs/promises-copyfile.js method="promise" n=20000: 260,925.24326093044
james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-copyfile.js
fs/promises-copyfile.js method="legacy" n=20000: 283,371.8168790678
fs/promises-copyfile.js method="promisify" n=20000: 154,272.6477009993
fs/promises-copyfile.js method="promise" n=20000: 177,795.42772743877
james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-copyfile.js
fs/promises-copyfile.js method="legacy" n=20000: 116,029.27694807078
fs/promises-copyfile.js method="promisify" n=20000: 154,155.65571356818
fs/promises-copyfile.js method="promise" n=20000: 92,732.89058694763
james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-copyfile.js
fs/promises-copyfile.js method="legacy" n=20000: 286,576.9026610743
fs/promises-copyfile.js method="promisify" n=20000: 69,093.89846983271
fs/promises-copyfile.js method="promise" n=20000: 83,583.96891906712
james@ubuntu:~/node/node$ ./node --no-warnings benchmark/fs/promises-copyfile.js
fs/promises-copyfile.js method="legacy" n=20000: 123,446.49834316899
fs/promises-copyfile.js method="promisify" n=20000: 157,543.37448739127
fs/promises-copyfile.js method="promise" n=20000: 150,655.3488844555

As illustrated by the benchmarks, the promise versions can be faster than the traditional callbacks, but the results are inconsistent. This appears largely to do with gc (there are a lot of promise objects created that need to be cleaned up).

Having the Promise version does not obsolete the callback version, as the creation and management of the promise objects can be fairly expensive.

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)

Merge request reports

Loading