背景
在用扫码枪扫货品的时候会调接口 每扫一个货品需要请求三个不同接口 在扫前40个货品的时候时间相差不大, 但是一直扫到150+货品的时候 就会出现 时间相差很大的情况
图一是接口返回的时间180ms 图三 从axios request 到 response 前 变成了 800ms
图四 在组件内发起请求到数据返回 时间变成了差不多1800ms 中间没做数据操作 只有增加了请求拦截和响应错误码处理 中间的时间相差这么多 是什么问题导致呢?
// import axios from 'axios'import axios, { AxiosRequestConfig, AxiosResponse, CancelTokenSource } from 'axios';import baseUrl, { differUrl } from './baseUrl';import router from '@/router';import store from '@/store';import { Message } from 'element-ui';import { vMessage } from '@rbp/components/base-message';import { filedMapData, moduleIdMapData } from './config';import { hideScreenLoading, showScreenLoading } from '@/utils/loading';import { getCookie, getToken, removeCookie } from '@/utils/auth';let configChace: any = null; // 存放请求参数,在进入错误时候也关掉loadingconst CANCELTTYPE = { CACHE: 1, REPEAT: 2};interface Request { onlyKey: string; url: string; source: CancelTokenSource;}const pendingRequests: Request[] = [];const config = { // timeout: 1000 * 60 * 10 // baseURL: baseUrl};// eslint-disable-next-line no-unused-varsconst _axios = axios.create(config);const DELAY = 0;let timer: any, loadingInstance: any;const setBaseUrl = (config) => { const initUrl = config.url; if (initUrl && initUrl.startsWith('/customize')) { config.baseURL = differUrl || baseUrl; config.baseURL = config.baseURL.replace('/manager', ''); config.timeout = 1000 * 60 * 10; } else if (initUrl && initUrl.startsWith('/report')) { config.baseURL = (Window as any).config.reportUrl || baseUrl; config.timeout = 1000 * 60 * 10; } else if (initUrl && initUrl.startsWith('/new-mf-fac')) { config.baseURL = localStorage.getItem('JuNiu_WebAddress') || baseUrl; config.timeout = 1000 * 60 * 10; } else { config.baseURL = baseUrl; config.timeout = 1000 * 60 * 3; }};const setToken = (config) => { const token = getToken(); const refreshToken = getCookie('refreshToken'); config.headers.Lang = getCookie('language') || 'zh_chs'; if (token) { config.headers['Authorization'] = token; // 让每个请求携带自定义token 请根据实际情况自行修改 } if (refreshToken) { config.headers['RefreshToken'] = refreshToken; }};const setModuleId = (config) => { const formatRouter: any = (window as any).__POWERED_BY_QIANKUN__ ? (window as any).ymyCustomizeRouter : router; // 模块 ID 参数 全局传入 // const moduleId = (router as any).history.current.meta.moduleId; // let moduleId = // (window as any).Vue2 && (window as any).Vue2.prototype // ? (window as any).Vue2.prototype._router_.history.current.meta.moduleId // : (router as any).history.current.meta.moduleId; let moduleId = (window as any).Vue2 && (window as any).Vue2.prototype ? (window as any).Vue2.prototype._router_.history.current.meta.moduleId : formatRouter.history.current.meta.moduleId; // 对于非/customize接口,替换moduleId为新moduleId if (config?.url.indexOf('/customize') < 0 && config?.url.indexOf('/role/authority') < 0) { const obj = moduleIdMapData(config.url, moduleId) || filedMapData(config.url, moduleId); if (obj?.moduleId) { config.url = obj.url; moduleId = obj.moduleId; if (config.params) { Object.keys(config.params).forEach((key) => { if (['baseModuleId', 'moduleId'].includes(key)) { config.params[key] = obj.moduleId; } }); } } } // if (moduleId && config.data) { // if (config.data && config.data.moduleId) { // Object.assign(config.data, { moduleId: config.data.moduleId }); // } if (moduleId && config.data) { // NetNeedModuleId 接口不需要 moduleId 为 true 则不需要加 if (config.data.NetNeedModuleId) { delete config.data.NetNeedModuleId; } else { if (Object.keys(config.data).indexOf('moduleId') > -1) { moduleId = config.data.moduleId; } Object.assign(config.data, { moduleId: moduleId }); if (typeof config.data.data === 'object') { if (config?.url.indexOf('/customize') < 0) { // 对于非/customize接口,将参数中moduleId替换为新moduleId if (Object.keys(config.data.data).indexOf('moduleId') > -1) { config.data.data.moduleId = moduleId; } } else { if (Object.keys(config.data.data).indexOf('moduleId') > -1 && config.data.data.moduleId) { moduleId = config.data.data.moduleId; } } Object.assign(config.data.data, { moduleId: moduleId }); } } if (config.data.setModuleIdInHeaders) { config.headers['moduleId'] = moduleId; delete config.data.setModuleIdInHeaders; } }};const setLoading = (config) => { configChace = config; // NetNeedModuleId 接口不需要 moduleId 为 true 则不需要加 if (config.method === 'get' && (!config.params || !config.params.NetNeedLoading)) { config.headers['showLoading'] = true; showScreenLoading(config.headers); } else if (['put', 'post'].includes(config.method) && (!config.data || !config.data.NetNeedLoading)) { config.headers['showLoading'] = true; showScreenLoading(config.headers); } config.params && delete config.params.NetNeedLoading; config.data && delete config.data.NetNeedLoading;};const preventSomeRequest = (config) => { /** * 为每一次请求生成一个cancleToken */ const source = axios.CancelToken.source(); config.cancelToken = source.token; /** * 将之前的重复且未完成的请求全部取消 */ const params = JSON.stringify(config.params || config.data); const hits = pendingRequests.filter((item) => item.onlyKey === `${config.baseURL}${config.url}${params}`); if (hits.length > 0) { console.error('有重复请求', hits, config); hits.forEach((item) => item.source.cancel(CANCELTTYPE.REPEAT.toString())); } pendingRequests.push({ onlyKey: `${config.baseURL}${config.url}${params}`, url: `${config.baseURL}${config.url!}`, source });};_axios.interceptors.request.use( function (config: AxiosRequestConfig) { // 全局请求的 loading,当请求 100 ms 后还没返回,才会出现 loading console.time('_axios.interceptors.request 请求设置header等等信息'); console.time('请求整理到返回中途所需要时间'); config.headers['request-startTime'] = new Date().getTime(); setBaseUrl(config); setToken(config); setModuleId(config); setLoading(config); // preventSomeRequest(config); console.timeEnd('_axios.interceptors.request 请求设置header等等信息'); return config; }, function (error) { // clearTimeout(timer); // if (loadingInstance) loadingInstance.close(); // if (config!.headers.showLoading) { if (configChace.headers['showLoading']) { hideScreenLoading(); configChace = null; } // } return Promise.reject(error); });// Add a response interceptor_axios.interceptors.response.use( function (response: AxiosResponse) { // clearTimeout(timer); // if (loadingInstance) loadingInstance.close(); const headers = response.config.headers; headers && headers.showLoading && hideScreenLoading(); /** * code为非20000是抛错 可结合自己业务进行修改 */ /** * 不论请求是否成功, * 将本次完成的请求从请求队列中移除 */ // 以同样的加密方式(MD5)获取加密字符串 const index = pendingRequests.findIndex((item) => item.url === response.config.url); // if (index > -1) { pendingRequests.splice(index, 1); } if (response.config.responseType === 'blob') { return response.data; } const res = response.data; const FIXCODE = [ 0, 10008, 10107, 10112, 10111, 10010, 20001, 30001, 30102, 30103, 30105, 30106, 40100, 40110, 40120, 40121, 40130, 40131, 40140, 40141, 40142, 40160, 40161, 40170, 40180, 50006, 50008, 50009, 50011, 50013, 50014, 50015, 50016, 50017, 50018, 50019, 50020, 50021, 50022, 50024, 50028, // 联营结算模式审核异常code码 50029, 50030, 50025, // 成本结存异常码(未做库存结存的渠道) 50031, // 成本结存异常码(存在以下未审核单据) 50032, // 成本结存异常码(存在本期数量未负的货品) 50033 ]; const NO_TOKEN_CODE = [10006]; // 没有权限或者和token失效 const PROGRAM_ERROR_CODE = [500, 10001, 10002]; // 显示错误具体信息弹窗 带复制等功能 console.timeEnd('请求整理到返回中途所需要时间'); if (PROGRAM_ERROR_CODE.includes(res.code)) { // Infrom({ type: 'error', content: res.msg, detail: res.errorStack, confirmButtonText: '关闭' }); Message({ type: 'error', message: res.msg, duration: 3500 }); return Promise.reject('error'); } else if (FIXCODE.includes(res.code)) { const start = response.config.headers['request-startTime']; const currentTime = new Date().getTime(); const requestDuration = ((currentTime - start) / 1000).toFixed(2) + 's'; console.log(`%caxios.ts line:288 ${response.config.url} 接口花费时间`, 'requestDuration', requestDuration); // return res; return Promise.resolve(res); } else if (NO_TOKEN_CODE.includes(res.code)) { //接口登陆失效跳转登录页 vMessage({ type: 'error', message: res.msg || res.errorStack, showClose: true, duration: 3500 }); removeCookie('tempToken'); removeCookie('tempRefreshToken'); store.dispatch('user/resetToken').then(() => { setTimeout(() => { window.location.reload(); }, 500); }); return Promise.reject('loginError'); } else { Message({ type: 'error', message: res.msg || res.errorStack, duration: 3500 }); return Promise.reject('error'); } }, function (error) { // clearTimeout(timer); // if (loadingInstance) loadingInstance.close(); // if (response.config.headers.showLoading) { // } // setTimeout(() => { // hideScreenLoading(); // }, 200); // 这里是重复请求不弹出 if (error.message !== CANCELTTYPE.REPEAT.toString()) { if (configChace.headers['showLoading']) { hideScreenLoading(); configChace = null; } // Infrom({ type: 'error', content: error.msg || '请求超时或服务器异常,请检查网络或联系管理员' }); Message({ type: 'error', message: error.msg || '请求超时或服务器异常,请检查网络或联系管理员' }); } return Promise.reject(error); });export default _axios;
这段时间涵盖的处理过程太多,尤其是网络过程非常不稳定。要先确定是哪部分造成报时间的大辐增加,如果是网络造成的,那前端不太可能做优化。
如果是想做纯粹的前端监测,从前端可以监测的点开始计时到当前处理不能监测时结束。比如你猜测是拦截引起的效率问题,那你可以只监测这部分处理所花的时间来确认是否是这个问题。
主要看图一的数据,延迟应该是服务端导致的吧,再延迟出现的时候,api的耗时是多少,请截图一的数据,分析一下
问题内容: 假设我有一个时间戳值的DataFrame : 我想创建一个新列。我可以通过编写一个简短的函数并使用它来迭代地创建它来创建它: 然后,我将看到以下结果: 什么我 想 实现的是这样一些较短的转变(我知道是错误的,但在精神得到): 显然,该列是类型的,因此没有这些属性,但是似乎有一种使用矩阵运算的简单方法。 有更直接的方法吗? 问题答案: 假设时间戳是数据帧的索引,则可以执行以下操作: 如果
我以为问题首先是与Postgres有关,但后来我发现不是。当我检查终端时,显示的是正确的日期。又名2021-04-15。但是,当我使用相同的查询将其返回到我的前端时,日期和时间是错误的。(终端中没有时间戳,但返回结果前端中有一个。这是我返回前端的代码。 我的前端代码如下。 我的前端正在以以下格式返回数据-2021-04-14T23:00:00.000Z。它目前是英国的第15届,它(在撰写本报告时)
问题内容: 我知道我可以使用momentjs做任何事情,还可以做一些涉及日期的事情。但是令人尴尬的是,我很难去做一件看起来很简单的事情:得到两次之间的差。 例: 我试过的 我不知道那里的“ 10”是什么。我住在巴西,所以如果相关的话,我们是utc-0300。 结果是持续时间正确的内部值: 所以,我想我的问题是:如何将momentjs持续时间转换为时间间隔?我肯定可以用 但我觉得有一些更 优雅 ,我
文档有点混乱。如果超时,该方法将返回什么?文件上写着“计算结果”,但如果计算超时怎么办?它是空的吗? 谢谢
我创建并持久化一个df1,然后在其上执行以下操作: 我有一个有16个节点的集群(每个节点有1个worker和1个executor,4个内核和24GB Ram)和一个master(有15GB Ram)。Spark.shuffle.Partitions也是192个。它挂了2个小时,什么也没发生。Spark UI中没有任何活动。为什么挂这么久?是dagscheduler吗?我怎么查?如果你需要更多的信息
当我想分析 Laravel 是如何做到从 Request -> Response 的解析过程的,发现 Lumen 相对简单,所以今天从 Lumen 源代码入手,说一说Request -> Response 的解析过程 载入 Router 我们使用 Lumen 项目时,都是通过创建 route,将请求的方法 method、路径 uri 和执行 action关联在一起,用于解析 Request。 如: