almost finished, TODO: handle thenable x of callback