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

简介: 常用!提前 reject promise 的 2 种场景,收藏等于学会

想一想,Promise 如何实现提前 reject?


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

一旦执行,我们无法知道它具体执行到哪里了,只知道在 pending,最后 resolve 或者 reject 才知道执行完毕。


image.png


但需要提前 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');
})


可以在码上掘金,打开控制台测测看。

code.juejin.cn/pen/7173900…


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;


控制台截图:

image.png


如果 N < 请求响应时间,则不会触发中断拦截;

code.juejin.cn/pen/7174026…

另外,要提一下的是,著名请求库 axios。也有中断请求的功能,同样是利用 promise 实现一个竞态限制,有兴趣可自行研究;

相关文章
|
5月前
|
前端开发
Promise 和 Async/await 在实际开发中的应用场景
Promise 和 Async/await 在实际开发中的应用场景
|
11月前
|
前端开发 JavaScript 开发者
什么是promise?如何使用?应用场景?
什么是promise?如何使用?应用场景?
82 0
|
前端开发 JavaScript
Promise和async/await的使用及其应用场景
Promise和async/await的使用及其应用场景
238 0
|
前端开发
Promise.all和promise.race的应用场景举例
Promise.all和promise.race的应用场景举例
217 0
|
5月前
|
前端开发 JavaScript
如何处理 JavaScript 中的异步操作和 Promise?
如何处理 JavaScript 中的异步操作和 Promise?
54 1
|
5月前
|
前端开发 JavaScript
在JavaScript中,什么是promise、怎么使用promise、怎么手写promise
在JavaScript中,什么是promise、怎么使用promise、怎么手写promise
79 4
|
5月前
|
前端开发 JavaScript 开发者
JavaScript 中的异步编程:Promise 和 Async/Await
在现代的 JavaScript 开发中,异步编程是至关重要的。本文将介绍 JavaScript 中的异步编程概念,重点讨论 Promise 和 Async/Await 这两种常见的处理异步操作的方法。通过本文的阐述,读者将能够更好地理解和应用这些技术,提高自己在 JavaScript 开发中处理异步任务的能力。
|
4月前
|
前端开发 JavaScript 开发者
JavaScript进阶-Promise与异步编程
【6月更文挑战第20天】JavaScript的Promise简化了异步操作,从ES6开始成为标准。Promise有三种状态:pending、fulfilled和rejected。基本用法涉及构造函数和`.then`处理结果,如: ```javascript new Promise((resolve, reject) =&gt; { setTimeout(resolve, 2000, &#39;成功&#39;); }).then(console.log); // 输出: 成功
72 4
|
5月前
|
JSON 前端开发 JavaScript
【JavaScript技术专栏】JavaScript异步编程:Promise、async/await解析
【4月更文挑战第30天】JavaScript中的异步编程通过Promise和async/await来解决回调地狱问题。Promise代表可能完成或拒绝的异步操作,有pending、fulfilled和rejected三种状态。它支持链式调用和Promise.all()、Promise.race()等方法。async/await是ES8引入的语法糖,允许异步代码以同步风格编写,提高可读性和可维护性。两者结合使用能更高效地处理非阻塞操作。
54 0
|
3月前
|
前端开发 JavaScript
JavaScript异步编程:Promise与async/await的深入探索
【7月更文挑战第9天】Promise和async/await是JavaScript中处理异步编程的两大利器。Promise为异步操作提供了统一的接口和链式调用的能力,而async/await则在此基础上进一步简化了异步代码的书写和阅读。掌握它们,将使我们能够更加高效地编写出清晰、健壮的异步JavaScript代码。