想一想,Promise 怎么完成提早 reject?

讲道理,咱们回忆下就知道 Promise 的特性就是:不能中止。

一旦履行,咱们无法知道它详细履行到哪里了,只知道在 pending,最终 resolve 或许 reject 才知道履行结束。

常用!提早 reject promise 的 2 种场景,保藏等于学会

但需求提早 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 错误信息;

那么,那对于第一个问题,就很好理解了:

  1. 点击按钮,建议恳求,再点击别的一个按钮,通过中止 Promise,撤销恳求;

完成过程拆解:

  1. 为了便利测验,咱们找一个可供在线测验的 API jsonplaceholder.typicode.com/posts GET 恳求能够直接拿到回来报文;
  2. 不凭借恳求库,就用原生 XHR;
  3. 为了加强模仿效果,咱们再用一个 setTimeout 函数,延伸成功回来的时刻,意思是:恳求至少要 10s+ 才会成功回来;
  4. 写一个大局的 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<300)){
				setTimeout(()=>{
					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');
})

能够在码上,翻开控制台测测看。

常用!提早 reject promise 的 2 种场景,保藏等于学会

p2

对于第 2 个问题:

  1. 用 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;

控制台截图:

常用!提早 reject promise 的 2 种场景,保藏等于学会

假如 N < 恳求响应时刻,则不会触发中止阻拦;

常用!提早 reject promise 的 2 种场景,保藏等于学会

别的,要提一下的是,著名恳求库 axios。也有中止恳求的功能,同样是利用 promise 完成一个竞态限制,有兴趣可自行研究;


OK,以上就是本篇共享,期望各位工友喜欢~ 欢迎点赞、保藏、谈论

我是安东尼 100 万人气前端技能博主 INFP 写作品格坚持 1000 日更文 ✍ 重视我,安东尼陪你一同度过漫长编程岁月

加我微信 ATAR53,拉你入群,定时抽奖、粉丝福利多多。只学习结交、不推文卖课~

我的公众号:安东尼,在上面,不止编程,更多还有生活感悟~

我的 GithubPage: tuaran.github.io,它现已被维护 4 年+ 啦~


本文正在参与「金石计划 . 瓜分6万现金大奖」