>[success] # 手动触发异步 * 大多数情况下异步都是内部触发,当想在某个节点自己去控制异步触发实际,可以对外去暴露`resolve`,`reject` ~~~ function defer() { const deferred = {} deferred.promise = new Promise((resolve, reject) => { deferred.resolve = resolve deferred.reject = reject }) return deferred } ~~~ * 使用时候完完全由外部控制,异步内部成功和失败 ~~~ const deferred = defer() deferred.resolve(1) deferred.promise.then((res) => { console.log(res) // 1 }) const deferred1 = defer() deferred1.reject(11) deferred1.promise.catch((res) => { console.log(res) // 11 }) ~~~ >[info] ## 用户抽奖 有若干个用户参与,每个用户从1到10中选择一个数字作为幸运数字,而系统一秒钟随机产生一个1到10的数字,若这个数字和用户的幸运数字相同,则该用户胜出 * 第一反应自己写的代码 缺点我们可以不使用Promise,直接将每一秒钟生成的数字与用户的数字逐一比较,选出胜出的用户。但是如果这样做,我们需要在定时器模块维护一个用户列表信息,这增加了代码的耦合。如果使用异步信号,则可以避免这样的耦合。 ~~~ // 奖池 class Jackpot { num = -1 users = [] // 注册用户 register(userInfo) { this.users.push(userInfo) } // 开始 start() { return this.users.find((item) => { return item.num === this.num }) } } // 用户奖池 const ls = [] const j = new Jackpot() j.register({ name: '1', num: 3 }) j.register({ name: '2', num: 5 }) j.register({ name: '3', num: 7 }) const timerID = setInterval(() => { const num = Math.ceil(Math.random() * 10) j.num = num const info = j.start() if (info) { console.log(info.name) clearInterval(timerID) } else { console.log('wu') } }, 1000) ~~~ * [前端工程师进阶 10 日谈](https://juejin.cn/book/6891929939616989188) 给的方案 ~~~ function defer() { const deferred = {} deferred.promise = new Promise((resolve, reject) => { deferred.resolve = resolve deferred.reject = reject }) return deferred } const _state = Symbol('state') const _checkers = Symbol('checker') class Signal { constructor(initState) { this[_state] = initState this[_checkers] = new Map() } get state() { return this[_state] } set state(value) { // 每次状态变化时,检查未结束的 defer 对象 ;[...this[_checkers]].forEach( ([promise, { type, deferred, state }]) => { if ( (type === 'while' && value !== state) || // 当信号状态改变时,while 信号结束 (type === 'until' && value === state) // 当信号状态改变为对应的 state 时,until 信号结束 ) { deferred.resolve(value) this[_checkers].delete(promise) } } ) this[_state] = value } while(state) { const deferred = defer() if (state !== this[_state]) { // 如果当前状态不是 while 状态, while 的 deferred 结束 deferred.resolve(this[_state]) } else { // 否则将它添加到 checkers 列表中等待后续检查 this[_checkers].set(deferred.promise, { type: 'while', deferred, state, }) } return deferred.promise } // 用来收集 用户信息保存在 _checkers 的map中 until(state) { const deferred = defer() if (state === this[_state]) { // 如果当前状态就是 until 状态, until 的 deferred 结束 deferred.resolve(this[_state]) } else { // 否则将它添加到 checkers 列表中等待后续检查 this[_checkers].set(deferred.promise, { type: 'until', deferred, state, }) } return deferred.promise } delete(promise) { this[_checkers].delete(promise) } deleteAll() { this[_checkers].clear() } } const lucky = new Signal() const timerID = setInterval(() => { const num = Math.ceil(Math.random() * 10) console.log(num) lucky.state = num // 去检查 是否有中奖 用户有就改变状态 }, 1000) async function addLuckyBoy(name, num) { await lucky.until(num) // 由于没有改变状态所以是 padding 状态 ,下面的代码不会执行 console.log(`${name} is lucky boy!`) clearInterval(timerID) lucky.deleteAll() // 删除checkers中的所有promise对象 } addLuckyBoy('张三', 3) addLuckyBoy('李四', 5) addLuckyBoy('王五', 7) ~~~