Skip to content

能否让$emit方法返回一个Promise对象。 #10421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
LastHeaven opened this issue Aug 22, 2019 · 2 comments
Closed

能否让$emit方法返回一个Promise对象。 #10421

LastHeaven opened this issue Aug 22, 2019 · 2 comments

Comments

@LastHeaven
Copy link

What problem does this feature solve?

能否让$emit方法返回一个Promise对象?这可以知道分发的事件在什么时候完成,方便在对这个事件进行监听的所有方法完成后进行一些额外的操作。
比如说,一个按钮组件,在点击之后变成加载中状态,在点击操作(这个操作可能是向服务器请求数据,也有可能仅仅只是个同步操作)完成之后,还原成之前的状态。这样的话,可以让按钮的状态变化与事件逻辑分离开。

What does the proposed API look like?

可以像下面一样的使用

{
  async onClick () {
     this.loading = true
     await this.$emit('click')
     this.loading = false
  }
}
@posva
Copy link
Member

posva commented Aug 22, 2019

you would need to pass some callback or resolve function as the emit payload. Otherwise, there is no way for the parent to tell that we are done:
Duplicate of #5443

You could implement a user land solution:

Vue.prototype.$asyncEmit = function (name, payload) {
  return new Promise((resolve, reject) => {
    this.$emit(name, { payload, resolve, reject })
  })
}

Then you could do something like this:

this.loading = true
await this.$asyncEmit('click')
this.loading = false

but the parent needs to resolve when it's done

@posva posva closed this as completed Aug 22, 2019
@LastHeaven
Copy link
Author

LastHeaven commented Aug 23, 2019

@posva
Can I use like this?

Vue.prototype.$asyncEmit = function (event) {
      const vm = this
      let cbs = vm._events[event]
      if (cbs) {
        cbs = cbs.length > 1 ? [...cbs] : cbs
        const args = [...arguments].slice(1)
        return cbs.map(cb => {
          const res = args ? cb.apply(vm, args) : cb.call(vm)
          if (isPromiseLike(res)) {
            return res
          } else {
            return new Promise(resolve => {
              resolve(res)
            })
          }
        })
      }
      return vm
    }

Then

async onClick () {
      this.loading = true
      const [res] = await Promise.all(this.$asyncEmit('click'))
      console.log('res', res)
      this.loading = false
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants