refactor to more decoupled and async style