port callback to promise