Reimplemented with promises, no API changes