前言
关于Promie
我这里就不多解释了,不懂得可以看看官方文档。下面文章重点介绍项目中遇到的问题解决方法。
需求
组件b初始化某个用到的库,只有在初始化完成后才能调用其API,不然会报错。a页面负责调用。
// a.vue
<template><div>这是a页面<childB ref="childB" /></div>
</template>
<script>
import childB from './b'
export default {mounted() {setTimeout(() => {this.$refs.childB.play()}, 3000)},components: {childB,},
}
</script>
// b.vue
<template><div>这是b页面</div>
</template>
<script>
export default {data() {return {flag: false,}},created() {this.init()},methods: {init() {setTimeout(() => {this.flag = true}, 2000)},play() {if (!this.flag) return console.log('not init')console.log('ok')},},
}
</script>
以上代码为模拟初始化,用setTimeout代替,实际开发中使用是一个回调函数,那么我页面a也是用setTimeout?写个5秒?10秒?有没有解决方案呢?
解决方案
// a.vue
<template><div>这是a页面<childB ref="childB" /></div>
</template>
<script>
import childB from './b'
export default {mounted() {this.init()},methods: {init() {setTimeout(() => {this.$refs.childB.play()}, 2000)},},components: {childB,},
}
</script>
// b.vue
<template><div>这是b页面</div>
</template>
<script>
export default {methods: {play() {console.log('ok')},},
}
</script>
相信这也是最常见也是大多数人使用的方案了,但是我觉得把b组件中的代码写到了a页面中,假如有多个b组件,那么a页面中要写多好的b组件代码。容易造成代码混淆、冗余,发生异常的错误,阻塞进程,这显然是不能接受的。
思考
我们能不能用promise来告诉我们是否已经完成初始呢?
答案当然是可以的!
// a.vue
<template><div>这是a页面<childB ref="childB" /></div>
</template>
<script>
import childB from './b'
export default {mounted() {const { init, play } = this.$refs.childBinit().then(play)},components: {childB,},
}
</script>
// b.vue
<template><div>这是b页面</div>
</template>
<script>
export default {methods: {init() {return new Promise(resolve => {setTimeout(() => {resolve()}, 2000)})},play() {console.log('ok')},},
}
</script>
不足
init在a页面mounted时候才触发,感觉太晚了。能不能在b组件created时候自行触发呢?
哈哈,当然可以了!
// a.vue
<template><div>这是a页面<childB ref="childB" /></div>
</template>
<script>
import childB from './b'export default {mounted() {this.$refs.childB.play()},components: {childB,},
}
</script>
// b.vue
<template><div>这是b页面</div>
</template>
<script>
function getPromiseWait() {let success, failconst promise = new Promise((resolve, reject) => {success = resolvefail = reject})return { promise, resolve: success, reject: fail }
}
const { promise, resolve } = getPromiseWait()
export default {created() {this.init()},methods: {init() {setTimeout(() => {resolve('hello')}, 2000)},async play() {const res = await promiseconsole.log('ok', res)},},
}
</script>
完美
我们在b组件中生成一个promise来控制是否init完成,a页面只需要直接调用b组件的play方法即可。如有需要还可以在resolve传递参数,通过then回调函授拿到数据,Promise。