常用!提前 reject promise 的 2 种场景,收藏等于学会 |
您所在的位置:网站首页 › 返回值是promise › 常用!提前 reject promise 的 2 种场景,收藏等于学会 |
想一想,Promise 如何实现提前 reject? 讲道理,我们回忆下就知道 Promise 的特性就是:不能中断。 一旦执行,我们无法知道它具体执行到哪里了,只知道在 pending,最后 resolve 或者 reject 才知道执行完毕。 但需要提前 reject的这种应用场景也确实是存在的。 比如: 1. 点击按钮,发起请求,再点击另外一个按钮,通过提前 reject Promise,不再依赖后续请求; 或 2. 用 Promise 封装异步请求,当超过 N 秒后还未执行完,提前 reject Promise ,执行后续操作; 这里的取消请求,并不是撤回 XHR 请求,而是不再需要请求结果,直接执行后面的步骤;p1如何实现? 不急,先想想,同步的中断 promise 的情况,它大概是这样的: function someAsyncFunction() { return new Promise(function(resolve, reject) { // 在这里执行异步操作 if (/* 某个条件成立 */) { // 如果条件成立,中断 promise reject(new Error("The promise was interrupted")); } }); } someAsyncFunction().catch(function(error) { // 处理 promise 中断的回调函数 console.error(error.message); });没什么毛病,如果某个条件成立,reject 错误信息; 那么,那对于第一个问题,就很好理解了: 点击按钮,发起请求,再点击另外一个按钮,通过中断 Promise,取消请求;实现步骤拆解: 为了方便测试,我们找一个可供在线测试的 API https://jsonplaceholder.typicode.com/posts GET 请求可以直接拿到返回报文;不借助请求库,就用原生 XHR;为了加强模拟效果,我们再用一个 setTimeout 函数,延长成功返回的时间,意思是:请求至少要 10s+ 才会成功返回;写一个全局的 cancelFn 方法,然后在 promise 内部重写它,当调用时,会直接 reject ,便实现了中断;const baseURL='https://jsonplaceholder.typicode.com/posts'; let cancelFn=function(){} function request(req){ return new Promise((resolve,reject)=>{ let xhr=new XMLHttpRequest(); xhr.open(req.method || 'GET',baseURL); xhr.onload=function(){ if(xhr.readyState==4 && (xhr.status>=200 && xhr.status{ resolve({data:JSON.parse(xhr.responseText)}) },10000) }else{ reject(xhr.status) } } xhr.onerror=function(){ reject('中断 promise...') } xhr.send(req.data || null); cancelFn=function(msg){ reject({message:msg}) } }) }; let send=document.querySelector('.send'); let cancel=document.querySelector('.cancel'); send.addEventListener('click',async function(){ console.log('正在请求中...') let {data}=await request({}) console.log(data) }); cancel.addEventListener('click',function(){ cancelFn('中断 promise'); })可以在码上掘金,打开控制台测测看。 https://code.juejin.cn/pen/7173900335335866407 p2对于第 2 个问题: 用 Promise 封装异步请求,当超过 N 秒后还未执行完,中断 Promise ,执行后续操作;解决这个问题,用到一个巧思: Promise.race: 一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。 我们把手动执行的超时中断,和业务逻辑的 prosmie 链条放在一起,超过 N 秒后,调用 cancelFn 方法,在 race 的 竞争策略 下,若 N 秒后请求还没返回,则直接 reject 返回,则实现了中断; 代码实现: const baseURL='https://jsonplaceholder.typicode.com/posts'; let cancelFn=function(){} let readUrlPromise=url=>{ return new Promise((resolve,reject)=>{ let xhr=new XMLHttpRequest(); xhr.open("GET",url); xhr.onreadystatechange=function(){ if(xhr.readyState==4 && xhr.status==200){ setTimeout(()=>{ resolve({data:JSON.parse(xhr.responseText)}) },3000) // 用 setTimeout 假设请求至少需要 3 s }else if(xhr.readyState==4 && xhr.status!=200){ reject('请求失败'); } } xhr.onerror=function(){ reject('请求失败'); } xhr.send(null); cancelFn=function(msg){ reject(msg); } }) } let rest=function(N){ return Promise.race([ readUrlPromise(baseURL), uploadTimeout(N) ]).then(data=>{ console.log('url1'); console.log(data); }) } function uploadTimeout(N){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ cancelFn('请求超时,中断promise') },N*1000) }) } rest(2) // 设定 2 s 后中断 promise;控制台截图: 如果 N < 请求响应时间,则不会触发中断拦截; https://code.juejin.cn/pen/7174026521235963912 另外,要提一下的是,著名请求库 axios。也有中断请求的功能,同样是利用 promise 实现一个竞态限制,有兴趣可自行研究; OK,本次分享如上,希望各位喜欢~ 欢迎点赞、收藏、评论 我是安东尼 100 万人气技术博主 INFP 写作人格坚持 1000 日更文 ✍ 关注我,安东尼陪你一起度过漫长编程岁月 另:威我 ATAR53,拉你入群,不定期抽奖、只学习交友、不推文卖课~ |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |