注册
web

原来Promise 还可以这样用?

举个例子


需求


组件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.childB
init().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>


嗯~ o( ̄▽ ̄)o 果然nice,干净整洁,一气呵成!


不足


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, fail
const promise = new Promise((resolve, reject) => {
success = resolve
fail = 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 promise
console.log('ok', res)
},
},
}
</script>



完美


我们在b组件中生成一个promise来控制是否init完成,a页面只需要直接调用b组件的play方法即可。如有需要还可以在resolve传递参数,通过then回调函授拿到数据,Pro

作者:𝓼𝓹𝓻𝓲𝓽𝓮𝓐𝓹𝓮
来源:juejin.cn/post/7225127360445841466
mise YYDS!

0 个评论

要回复文章请先登录注册