JavaScript实现锁功能,同一时间多次异步请求函数都取到返回值,只触发一次异步请求 | 您所在的位置:网站首页 › js返回一个函数怎么操作 › JavaScript实现锁功能,同一时间多次异步请求函数都取到返回值,只触发一次异步请求 |
问题
有个需求,某个异步请求函数可能被多次调用,重复调用消耗资源,需要对其进行优化 每次调用该函数都能取到返回值只发送一次异步请求这个和节流、防抖功能不一样,节流防抖会丢弃掉中间的请求,中间的请求获取不到返回值,这里要求每一个函数调用都能取到返回值。 方案一很容易想到使用同步非阻塞方案,在第一个点击时,进入loading状态,之后的点击判断loading就等50毫秒继续检查loading的值,直到loading为false,返回localEnv。这里使用setTimeout来模拟异步请求。 async function clickMe() { const env = await getEnv() console.log(env) } let localEnv let loading = false async function getEnv() { if (localEnv) { return localEnv } // 若正在请求中,则每50毫秒检查loading状态,直到为false,返回请求结果 if (loading) { // 同步非阻塞 while(loading) { await wait(50) } return localEnv } else { loading = true return new Promise((resolve, reject) => { console.log('questing env......') setTimeout(() => { localEnv = { platform: '141001', appid: 'aoshdakhpa8fkdng' } loading = false resolve(localEnv) }, 2000) }) } } function wait (time) { return new Promise(resolve => { setTimeout(() => { resolve() }, time) }) }方案一主要由于循环去检测loading的状态,导致不那么高效 方案二Java中可以通过锁机制,使用wait/notify轻易实现该功能。JavaScript也可以利用锁机制来实现类似wait/notify的功能。 JavaScript可以通过resolve/reject函数来实现锁,在没有调用resolve/reject函数时,promise会看起来相当于一直阻塞(其实和Java的阻塞不一样,这里只是没有执行后续的函数)。 async function clickMe() { const env = await getEnv() console.log(env) } let localEnv, p const queue = [] let loading = false async function getEnv() { return new Promise((resolve, reject) => { if (localEnv) { resolve(localEnv) } // 进入这个if的Promise没有调用resolve(),会一直阻塞 if (loading) { // 把resolve存入数组,待请求返回后执行resolve queue.push({resolve, reject}) } if (!loading && !localEnv) { loading = true console.log('questing env......') setTimeout(() => { localEnv = { platform: '141001', appid: 'aoshdakhpa8fkdng' } loading = false resolve(localEnv) // 异步请求结束,调用所有正在阻塞的Promise的resolve函数,返回结果,解除阻塞 while (p = queue.shift()) { p.resolve(localEnv) } }, 2000) } }) } 结语利用好Promise没有resolve/reject会一直阻塞的特性,可以实现类似Java的wait/notify功能,实现同一时间多次异步请求函数都取到返回值,只触发一次异步请求的功能。 |
CopyRight 2018-2019 实验室设备网 版权所有 |