面经总结1

如何保证批量请求失败,只弹出一个toast

1使用计数器:

初始化一个计数器,记录失败请求的数量。每当请求失败(完成)时,计数器加一。
在所有请求结束后检查计数器的值,如果等于请求总数,则弹出toast。

2使用标志变量:

设置一个标志变量,默认为false。当第一个请求失败时,将标志变量设置为true。
后续的请求失败后,检查这个标志变量,如果是true则不再进行设置,确保toast只弹出一次。
在所有请求结束后,检查标志变量,如果是true则弹出toast。

所有的请求都通过Promise.all来[并行处理] ,最后检查结果数组中是否有失败的情况,并且确保只弹出一个toast。


function batchRequest(urls) {
  let hasFailed = false;
 
  const promises = urls.map(url => {
    return request(url).catch(error => {
      if (!hasFailed) {
        hasFailed = true;
      }
      return error; // 返回错误,但不直接处理
    });
  });
  Promise.all(promises).then(results => {
    // 检查是否有失败的请求
    if (results.some(result => result === 'Failure')) {
      if (hasFailed) {
        showToast('所有请求均失败');
      }
    }
  });
}

如何减少项目里的if-else

1使用多态

将if else语句中的不同分支封装成不同的类,并定义一个共同的接口或基类,通过调用接口或基类的方法来执行相应的逻辑。这样可以将条件判断转移到对象的创建阶段,减少代码中的条件判断语句。

在 JavaScript 中,可以使用对象和函数来实现多态,从而减少 if-else 语句的使用。以下是一个示例:

// 定义一个基类(抽象类)
class Animal {
  makeSound() {
    throw new Error("makeSound 方法必须在子类中实现");
  }
}

// 定义多个子类,每个子类代表一种动物
class Dog extends Animal {
  makeSound() {
    return "汪汪汪";
  }
}

class Cat extends Animal {
  makeSound() {
    return "喵喵喵";
  }
}

class Bird extends Animal {
  makeSound() {
    return "叽叽叽";
  }
}

// 定义一个函数,接收一个 Animal 类型的对象,并调用其 makeSound 方法
function playSound(animal) {
  console.log(animal.makeSound());
}

// 创建不同类型的动物对象
const dog = new Dog();
const cat = new Cat();
const bird = new Bird();

// 调用 playSound 函数,传入不同的动物对象
playSound(dog); // 输出:汪汪汪
playSound(cat); // 输出:喵喵喵
playSound(bird); // 输出:叽叽叽

在这个示例中,我们定义了一个 Animal 基类和多个子类(DogCatBird),每个子类都有一个 makeSound 方法。然后,我们定义了一个 playSound 函数,它接收一个 Animal 类型的对象,并调用其 makeSound 方法。这样,我们就可以通过多态来减少 if-else 语句的使用。

2使用策略模式

将if else语句中的不同分支封装成不同的策略类,每个策略类实现一种特定的逻辑。通过将策略类作为参数传递给一个统一的执行方法,根据不同的情况选择相应的策略类执行逻辑。这样可以将条件判断转移到方法的调用阶段,减少代码中的条件判断语句。

3使用字典映射

将if else语句中的不同分支作为字典的键值对,根据条件选择相应的键,然后通过字典获取对应的值执行相应的逻辑。这样可以将条件判断转移到字典的查找过程,减少代码中的条件判断语句。

4使用状态模式

将if else语句中的不同分支封装成不同的状态类,每个状态类表示一种特定的状态,并定义相应的方法。通过将状态类作为属性保存在一个上下文对象中,根据不同的情况切换状态,并调用相应状态类的方法执行逻辑。这样可以将条件判断转移到状态的切换过程,减少代码中的条件判断语句。

babel-runtime 作用是啥

babel-runtime主要作用就是**将在使用 babel 进行代码转换时可能被重用的代码抽取成单独的模块,以避免在每个文件中重复出现相同的代码。**它通过模块导入的方式引入这些功能,从而避免了对全局作用域的修改或污染。

使用 babel-runtime 通常需要配合 babel-plugin-transform-runtime 插件一起使用。babel-plugin-transform-runtime 插件会进行一些处理,例如自动导入 babel-runtime/core-js,并将全局静态方法、全局内置对象映射到对应的模块;将内联的工具函数移除,改成通过 babel-runtime/helpers 模块进行导入;如果使用了 async/generator 函数,则自动导入 babel-runtime/regenerator 模块等。

这样,在代码中如果需要使用特定的功能,只需从 babel-runtime 相应的模块中导入即可,而不是直接使用全局的对象或函数。

如何实现 PDF 预览和下载

1浏览器内置PDF阅读器

浏览器内置PDF阅读器 是实现PDF文件预览的最直接方式。用户只需在HTML中插入<embed><iframe>标签,并设定其src属性为PDF文件的URL即可。

<embed src="path/to/your-document.pdf" type="application/pdf" width="100%" height="600px">
<iframe src="path/to/your-document.pdf" width="100%" height="600px"></iframe>

浏览器会自动调用内置的PDF阅读器插件来显示PDF内容,实现预览效果。这种方法的优点是简单快捷、不依赖外部库,但可能在PDF文件较复杂或需要额外交互时遇到限制

2使用PDF.js库

使用JavaScript库PDF.js 是另外一种流行的方式,它是一个通用的、兼容各主流浏览器的PDF阅读器。PDF.js使用HTML5的Canvas API对PDF文件进行渲染,使其能在不支持插件的情况下工作。

要使用PDF.js,你需要首先引入该库:

<script src="https://mozilla.github.io/pdf.js/build/pdf.js"></script>

随后,你可以通过JavaScript代码加载PDF文件,并在指定的Canvas上渲染出来:

pdfjsLib.getDocument('path/to/your-document.pdf').promise.then(function(pdfDoc) {
  pdfDoc.getPage(1).then(function(page) {
    var canvas = document.getElementById('pdf-canvas');
    var context = canvas.getContext('2d');
    var viewport = page.getViewport({scale: 1});
    canvas.height = viewport.height;
    canvas.width = viewport.width;
    var renderContext = {
      canvasContext: context,
      viewport: viewport
    };
    page.render(renderContext);
  });
});

3后端服务生成图像预览

在一些情况下,前端直接处理PDF文件可能不是最佳选择,尤其是涉及到安全性或者性能时。这时你可以选择后端服务生成图像预览

后端服务可以用第三方库,如Python的PyMuPDF或Java的Apache PDFBox,来处理PDF文件,将其转换成图片并发送到前端

这种方法的优点是前端不需要处理复杂的文件渲染,降低了前端的计算和渲染压力。不过,这也意味着增加了后端的处理负载,并需要处理前后端之间的文件传输。

前端请求中断的方式和原理

1 Axios.CancelToken

axios对象有一个属性叫CancelToken,该属性提供了中断已经发出去的请求的方式。具体使用方式有两种:

方式一:执行器模式

const CancelTokenFunc = axios.CancelToken;
let cancel;
// 发送请求
axios.get("https://jsonplaceholder.typicode.com/todos/1", {
	cancelToken: new CancelTokenFunc(function executor(c) {
        // 将 cancel 函数赋值给外部变量
        cancel = c;
	}),
}).catch((error) => {console.log(error.message);});
// 取消请求
setTimeout(() => {cancel("Operation canceled by the user.");}, 1000);

先获取一个中断构造函数CancelTokenFunc,用这个构造函数new出一个实例赋值给get请求的参数cancelToken字段。

在调用CancelTokenFunc构造函数new出一个实例的时候,我们传入了一个执行器函数,该执行器会接受一个参数,这个参数就是用来控制中断请求的取消函数,接着我们把该参数函数赋值给外部变量,这样就可以在外部需要的时候执行中断请求的操作。

方式二:令牌模式

// 创建一个 CancelToken 源
const CancelTokenFunc = axios.CancelToken;
const { token, cancel } = CancelTokenFunc.source();
// 发送请求
axios.get("https://jsonplaceholder.typicode.com/todos/1", {
    cancelToken: token,
  }).catch((error) => {
    console.log(error.message);
  });
// 取消请求
setTimeout(() => {cancel("Operation canceled by the user.")}, 1000);

CancelTokenFuncsource方法生成一个取消令牌源,并从取消令牌源中解构出tokencancel字段,然后在GET请求中将取消令牌源的token传递给cancelToken,接着在外部调用请求令牌源的cancel方法来取消请求。

2 AbortController

AbortController是一个Web API,用于控制和管理可中止的异步操作,例如 fetch 请求、DOM 操作。接下来我们看看怎么用AbortController来中止请求。

// 创建一个 AbortController 信号源
const controller = new AbortController();
const { signal } = controller;
 // 发送请求
fetch("https://jsonplaceholder.typicode.com/todos/1", {
    signal,
}).catch((error) => {
    console.log(error);
});
// 取消请求
setTimeout(() => {
	controller.abort("Operation canceled by the user.");
}, 1000);

创建一个AbortController信号源,在fetch请求的时候传递一个信号给请求的signal参数,之后便可以在请求的外部通过调用信号源的abort方法来取消请求。

令牌中断请求原理

cancelToken需要携带一个回调属性,在外界执行cancel方法时触发回调。

cancelToken挂载一个Promise实例的属性,然后将这个Promise属性的resolved方法传递给cancel,当执行cancel函数的时候,其实就是执行resolve(),从而改变Promise实例的状态,我们就能在Promise实例的then方法中执行需要的操作。

function fetchData(url, options = {}) {
  const { cancelToken } = options;

  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);

    // 监听请求状态变化,处理请求的常规逻辑
    // 其他代码

     // 监听取消请求
        if (cancelToken) {    
            // 需要在外界调用cancel请求的时候,调用xhr.abort()方法中止请求     
            // 并调用reject函数将Promise对象的状态改成rejected    
            cancelToken.promise.then((msg) => {     
                xhr.abort();     
                reject(new Error(msg));    
            })   
        }
      xhr.send();
  });
}

token声明为对象,并给token添加一个promise属性,该属性是一个Promise实例,并且将Promise实例的resolve方法传递给了cancel变量,当调用执行cancel()的时候,就是在执行resolve()tokenpromise属性就能触发then回调函数.

function CancelToken() {}
CancelToken.source = function () {
  let cancel;
  const token = {
    promise: new Promise((resolve) => {cancel = resolve})
  };
  return {
    cancel,
    token,
  };
};

执行器模式原理

  1. this上挂载了promise属性,该属性是一个Promise对象,同时,为了达到在外部触发该Promise对象的状态变更,我们将其resolve方法保存给了外部变量resolvePromise
  2. 声明构造函数的时候声明了executor入参。
  3. 在执行器调用的时候传入一个函数作为入参,同时在函数内部执行resolvePromise()触发this.promise状态变更。
function CancelToken(executor) {
  let resolvePromise;
  this.promise = new Promise((resolve) => { resolvePromise = resolve;});
 
  executor(function c() {
    resolvePromise();
  })
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值