JavaScript常见高级知识点

目录

  • 防抖
  • 节流
  • 高阶函数
  • 函数柯里化
  • 数组去重
    • set去重
    • filter去重
    • includes去重
  • 数组扁平化
  • 深拷贝
  • getBoundingCilentRect
  • IntersectionObserver
  • 自定义事件

防抖

防抖是一种常用的技术手段,在JavaScript中特别常见。它的作用是控制某些高频率触发的事件,在一定时间内只执行一次,从而减少不必要的资源消耗。以下是一个防抖的案例:

// 假设有一个输入框,需要实时响应用户输入
const input = document.querySelector('#input');
let timeout;function debounce(func, delay) {clearTimeout(timeout);timeout = setTimeout(func, delay);
}// 当用户输入时触发的事件处理函数
function handleInput() {console.log(input.value);// 做其他操作...
}// 使用防抖来控制输入事件的触发频率
input.addEventListener('input', function() {debounce(handleInput, 300); // 在300毫秒内只执行一次handleInput函数
});

在上面的示例中,输入框的input事件会触发handleInput函数,但是通过使用debounce函数,在300毫秒内只会执行一次handleInput函数。这样可以避免频繁响应用户输入导致的性能问题。

防抖在实际开发中还有很多应用场景,比如监听窗口大小改变、滚动事件等。通过合理地运用防抖技术,可以提升用户体验和页面性能。

节流

节流是另一种常见的技术手段,用于控制某些高频率触发的事件,在一定时间间隔内执行一次。下面是一个节流的案例:

// 假设有一个按钮,点击时需要发送请求
const button = document.querySelector('#button');
let canClick = true;function throttle(func, delay) {if (canClick) {canClick = false;setTimeout(function() {func();canClick = true;}, delay);}
}// 点击事件的处理函数
function handleClick() {console.log('发送请求');// 做其他操作...
}// 使用节流来控制点击事件的触发频率
button.addEventListener('click', function() {throttle(handleClick, 1000); // 在1000毫秒内只执行一次handleClick函数
});

在上面的示例中,按钮的点击事件会触发handleClick函数,但是通过使用throttle函数,在1000毫秒内只会执行一次handleClick函数。这样可以避免频繁点击导致的重复请求或其他问题。

节流在实际开发中也有许多应用场景,比如限制事件的触发频率,如鼠标移动事件、滚动事件等。通过合理地运用节流技术,可以控制事件的执行频率,从而提升性能和用户体验。

高阶函数

高阶函数是指接收一个或多个函数作为参数,并返回一个新的函数的函数。它在函数式编程中具有重要的作用,可以用于实现函数的复用、组合和抽象等。以下是一个高阶函数的案例:

// 假设有一个计算函数执行时间的高阶函数
function calculateExecutionTime(func) {return function() {const start = performance.now();const result = func.apply(this, arguments);const end = performance.now();console.log(`函数执行时间为:${end - start}毫秒`);return result;}
}// 普通的函数
function add(a, b) {return a + b;
}// 使用高阶函数计算add函数的执行时间
const timedAdd = calculateExecutionTime(add);// 调用新的函数
timedAdd(1, 2); // 输出:函数执行时间为:0.0249999229毫秒,返回:3

在上面的示例中,calculateExecutionTime是一个高阶函数,它接收一个函数作为参数,并返回一个新的函数。返回的新函数在执行时会先记录函数开始执行的时间,然后调用原函数,最后计算函数执行的时间并输出。

通过使用高阶函数,我们可以复用calculateExecutionTime函数来计算其他函数的执行时间,而无需重复编写计时逻辑。这提供了一种抽象和代码复用的机制,提高了代码的可维护性和可读性。

除了计算执行时间,在实际开发中还可以使用高阶函数来实现其他功能,如错误处理、日志记录、缓存等。高阶函数为函数式编程提供了丰富的工具和思路。

函数柯里化

函数柯里化是一种将多参数函数转化为一系列单参数函数的技术,使得函数更加灵活和可复用。以下是一个函数柯里化的案例:

// 假设有一个加法函数
function add(a, b, c) {return a + b + c;
}// 使用函数柯里化将多参数函数转化为单参数函数
function curry(func) {return function curried(...args1) {if (args1.length >= func.length) {return func.apply(this, args1);} else {return function(...args2) {return curried.apply(this, args1.concat(args2));}}};
}// 对add函数进行柯里化
const curriedAdd = curry(add);// 调用柯里化后的函数
console.log(curriedAdd(1)(2)(3)); // 输出:6
console.log(curriedAdd(1, 2)(3)); // 输出:6
console.log(curriedAdd(1)(2, 3)); // 输出:6
console.log(curriedAdd(1, 2, 3)); // 输出:6

在上面的示例中,curry是一个函数柯里化的高阶函数。它接收一个多参数函数作为参数,并返回一个经过柯里化处理后的新函数。返回的新函数可以接收单个参数,在参数收集到足够数量后,就会执行原函数。

通过对add函数进行柯里化,我们可以使用不同的方式来调用柯里化后的函数。不论是逐个传入参数,还是一次传入多个参数,最终都能得到正确的结果。

函数柯里化可以用于实现参数复用、函数组合以及延迟执行等功能。它提供了一种灵活的方式来处理函数和参数,增强了代码的可读性和可维护性。

数组去重

set去重

使用ES6中的Set数据结构可以很方便地实现数组的去重操作。Set是一种无重复值的有序集合,它只会存储唯一的值。下面是一个使用Set进行数组去重的案例:

const array = [1, 2, 3, 3, 4, 5, 5];
const uniqueArray = [...new Set(array)];console.log(uniqueArray); // 输出:[1, 2, 3, 4, 5]

在上面的示例中,我们定义了一个数组array,其中包含了一些重复的元素。通过使用new Set(array),我们可以将数组转换为一个Set对象,Set会自动去除重复的值。然后,通过扩展运算符[...new Set(array)]将Set对象转化回数组,就得到了去重后的uniqueArray

需要注意的是,Set返回的是一个迭代器对象,而不是一个数组。为了将其转化回数组,我们使用扩展运算符[...new Set(array)],将Set对象中的值取出并放入一个新的数组中。

这种方法简洁高效,适用于基本类型和引用类型的数组。然而,如果数组中的元素是复杂的对象,则需要注意对象之间的引用关系,因为Set进行去重是基于严格相等比较(===)的。如果需要对复杂对象进行深度去重,需要使用其他的方法。

filter去重

使用filter方法可以实现数组的去重操作。filter方法接收一个回调函数作为参数,遍历数组的每个元素,并根据回调函数的返回值决定是否保留该元素。下面是一个使用filter进行数组去重的案例:

const array = [1, 2, 3, 3, 4, 5, 5];
const uniqueArray = array.filter((value, index, self) => {return self.indexOf(value) === index;
});console.log(uniqueArray); // 输出:[1, 2, 3, 4, 5]

在上面的示例中,我们使用filter方法对数组array进行遍历,对于每个元素,我们通过indexOf方法判断在数组中第一次出现的索引是否和当前的索引相同。如果相同,说明当前元素是第一次出现,保留该元素,否则过滤掉重复的元素。

通过这种方式,filter方法会创建一个新的数组uniqueArray,其中只包含不重复的元素。

需要注意的是,indexOf方法在遇到引用类型的元素时可能无法正确判断是否重复,因为引用类型的比较是基于引用地址的。在处理复杂对象的数组去重时,可能需要使用其他方法,如使用reduce方法结合自定义的比较函数进行去重操作。

includes去重

使用includes方法可以在数组中检查是否包含某个特定的元素。尽管includes方法本身并不能直接实现数组的去重,但结合filter或其他数组方法,可以间接地实现数组去重的效果。下面是一个使用includes进行数组去重的案例:

const array = [1, 2, 3, 3, 4, 5, 5];
const uniqueArray = array.filter((value, index, self) => {return self.indexOf(value) === index && self.includes(value);
});console.log(uniqueArray); // 输出:[1, 2, 3, 4, 5]

在上面的示例中,我们使用filter方法对数组array进行遍历,对于每个元素,我们通过indexOf方法判断在数组中第一次出现的索引是否和当前的索引相同,同时使用includes方法判断数组中是否包含当前的元素。如果满足这两个条件,就保留该元素,即实现了去重操作。

通过结合使用indexOfincludes方法,我们可以在保留数组中第一个出现的重复元素的同时,过滤掉其余的重复元素,从而得到去重后的uniqueArray

需要注意的是,与上述提到的方法一样,当处理复杂对象的去重时,需要使用其他的方法来进行深度比较,并根据具体需求来实现去重的逻辑。

数组扁平化

数组扁平化指的是将多层嵌套的数组转化为一层的数组。这种操作可以简化数组的处理和遍历过程。下面介绍几种实现数组扁平化的常用方法:

  1. 使用Array.prototype.flat方法(ES2019)

    const nestedArray = [1, [2, [3, 4]]];
    const flattenedArray = nestedArray.flat(Infinity);console.log(flattenedArray); // 输出:[1, 2, 3, 4]
    

    flat方法接收一个可选的扁平化深度参数,默认为1。通过传递Infinity作为参数,可以完全扁平化多层嵌套的数组。

  2. 使用递归和concat方法

    function flattenArray(array) {let flattenedArray = [];array.forEach(item => {if (Array.isArray(item)) {flattenedArray = flattenedArray.concat(flattenArray(item));} else {flattenedArray.push(item);}});return flattenedArray;
    }const nestedArray = [1, [2, [3, 4]]];
    const flattenedArray = flattenArray(nestedArray);console.log(flattenedArray); // 输出:[1, 2, 3, 4]
    

    上述代码中,flattenArray函数通过递归地处理每个元素,如果元素是数组,则继续递归地扁平化;如果不是数组,则直接将元素加入到结果数组中。

  3. 使用reduce方法

    function flattenArray(array) {return array.reduce((result, item) => {if (Array.isArray(item)) {return result.concat(flattenArray(item));} else {return result.concat(item);}}, []);
    }const nestedArray = [1, [2, [3, 4]]];
    const flattenedArray = flattenArray(nestedArray);console.log(flattenedArray); // 输出:[1, 2, 3, 4]
    

    reduce方法通过遍历数组的每个元素,将元素累积到一个结果数组中。如果元素是数组,则递归地扁平化后再进行累积;如果元素不是数组,则直接累积到结果数组中。

无论通过哪种方法实现数组扁平化,都可以将多层嵌套的数组转化为一层的数组,便于后续的处理和操作。

深拷贝

深拷贝是指创建一个完全独立于原始对象的副本,包括所有嵌套的对象和数组。深拷贝确保修改副本不会影响原始对象。下面介绍几种常见的实现深拷贝的方法:

  1. 使用 JSON 序列化与反序列化

    const originalObj = { a: 1, b: { c: 2 } };
    const clonedObj = JSON.parse(JSON.stringify(originalObj));console.log(clonedObj); // 输出:{ a: 1, b: { c: 2 } }
    

    通过先将原始对象转换为JSON字符串,然后使用JSON.parse方法将字符串转换回对象,就能实现深拷贝。这种方法适用于大多数可以转换为JSON的数据类型,但它存在一些限制,比如无法拷贝函数、循环引用等。

  2. 使用递归实现深拷贝

    function deepClone(obj) {if (typeof obj !== 'object' || obj === null) {return obj; // 处理基本类型和null}let clonedObj = Array.isArray(obj) ? [] : {}; // 创建与原始对象类型相同的空对象或空数组for (let key in obj) {if (obj.hasOwnProperty(key)) {clonedObj[key] = deepClone(obj[key]); // 递归调用深拷贝}}return clonedObj;
    }const originalObj = { a: 1, b: { c: 2 } };
    const clonedObj = deepClone(originalObj);console.log(clonedObj); // 输出:{ a: 1, b: { c: 2 } }
    

    上述代码中,deepClone函数使用递归实现深拷贝。它遍历原始对象的每个属性,并对属性值进行递归调用,以确保所有嵌套的对象和数组也被深拷贝。

  3. 使用第三方库实现深拷贝
    在 JavaScript 社区中有许多流行的第三方库,如lodash、underscore等,提供了方便的深拷贝函数。这些库通常具有更复杂的逻辑,可以处理各种特殊情况,并提供更高级的拷贝功能。你可以选择其中一个库,根据其文档使用深拷贝函数。

无论使用哪种方法,深拷贝都可以创建一个原始对象的完全独立副本。需要注意的是,在处理特殊对象类型(如函数、正则表达式、循环引用等)时,需要特别留意深拷贝的实现方式。

getBoundingCilentRect

getBoundingClientRect 是一个 DOM 元素方法,用于获取元素的大小和位置信息。它返回一个 DOMRect 对象,其中包含了与元素相关的位置、宽度、高度等属性。下面是一个使用 getBoundingClientRect 方法的示例:

const element = document.getElementById('myElement');
const rect = element.getBoundingClientRect();console.log(rect); // 输出:DOMRect 对象
console.log(rect.width); // 输出:元素的宽度
console.log(rect.height); // 输出:元素的高度
console.log(rect.top); // 输出:元素顶部相对于视口的距离
console.log(rect.bottom); // 输出:元素底部相对于视口的距离
console.log(rect.left); // 输出:元素左侧相对于视口的距离
console.log(rect.right); // 输出:元素右侧相对于视口的距离

在上述示例中,我们通过 getElementById 方法获取到一个 DOM 元素,并将其赋值给变量 element。然后,我们使用 getBoundingClientRect 方法获取该元素的大小和位置信息,并将结果保存在 rect 变量中。

接下来,我们可以通过 rect 对象获取元素的各种属性,如 widthheighttopbottomleftright。这些属性提供了元素相对于视口的位置和尺寸信息,可以在计算布局或进行其他各种操作时使用。

需要注意的是,getBoundingClientRect 方法返回的是一个只读的 DOMRect 对象,它在每次调用时都会重新计算元素的位置和尺寸。如果元素的样式或布局发生变化,需要重新调用 getBoundingClientRect 方法以获取最新的信息。此外,返回的值是相对于视口的位置,而不是相对于文档的位置。如果需要相对于文档的位置,可以通过加上 window.scrollXwindow.scrollY 来计算。

IntersectionObserver

Intersection Observer 是一个新的 JavaScript API,用于异步观察目标元素与其祖先元素或文档视口之间的交叉状态。它可以用于检测目标元素是否进入、退出或部分可见于其祖先元素或视口。

使用 Intersection Observer 的主要目的是观察元素的可见性,而无需连续监测和处理滚动事件。这在需要有效地处理大量元素或需要实时响应元素可见性变化的情况下非常有用。

下面是一个使用 Intersection Observer 的简单示例:

// 创建一个 Intersection Observer 实例
const observer = new IntersectionObserver(entries => {entries.forEach(entry => {if (entry.isIntersecting) {console.log('目标元素可见');} else {console.log('目标元素不可见');}});
});// 监听目标元素
const targetElement = document.querySelector('#myElement');
observer.observe(targetElement);

在上述示例中,我们首先创建了一个 Intersection Observer 实例 observer,通过构造函数传入一个回调函数。回调函数会在监听的目标元素进入或退出视口时被触发,它接收一个包含交叉信息的 entries 数组。

然后,我们选择要观察的目标元素并使用 observe 方法将其添加到 Intersection Observer 实例中进行监测。当目标元素进入或退出视口时,回调函数将根据 entry.isIntersecting 属性判断目标元素的可见性,并输出相应的信息。

除了上述示例中的基本用法,Intersection Observer 还提供了更多功能,如设置阈值、使用根元素、观察多个目标元素等。你可以参考相关文档深入了解 Intersection Observer 的更多用法和选项。

自定义事件

在 JavaScript 中,你可以创建自定义事件来实现自定义的事件处理逻辑。自定义事件使你能够在代码中触发和订阅特定的事件,并在需要时执行相应的操作。下面是一个简单的示例来演示如何创建和使用自定义事件:

// 创建自定义事件对象
const customEvent = new Event('myEvent');// 监听自定义事件
document.addEventListener('myEvent', () => {console.log('自定义事件被触发');
});// 触发自定义事件
document.dispatchEvent(customEvent);

在上面的示例中,我们首先创建了一个自定义事件对象 customEvent,通过 Event 构造函数传入事件名称。然后,我们使用 addEventListener 方法在文档上订阅了 myEvent 事件,并定义了事件处理程序。最后,通过 dispatchEvent 方法在文档上触发了自定义事件。

当自定义事件被触发时,事件处理程序就会执行,并输出相应的消息到控制台上。

此外,你还可以向自定义事件对象添加更多的数据,以便在事件处理程序中使用。你可以使用 CustomEvent 构造函数来创建带有自定义数据的事件对象。例如:

// 创建带有自定义数据的事件对象
const customEvent = new CustomEvent('myEvent', {detail: {message: 'Hello, world!'}
});// 监听自定义事件
document.addEventListener('myEvent', event => {console.log(event.detail.message); // 输出:Hello, world!
});// 触发自定义事件
document.dispatchEvent(customEvent);

在上述示例中,我们使用 CustomEvent 构造函数来创建自定义事件对象,并通过 detail 属性添加了一个 message 属性。在事件处理程序中,我们可以通过访问 event.detail 来获取传递的自定义数据。

通过自定义事件,你可以根据需要定义和触发特定的事件,以实现更灵活和定制化的事件处理逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/7215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RocketMQ消息过滤Tag标签

生产者在封装Message消息时可以传入tag参数,消费者在进行消费时可以进行订阅主题时可以进行tag过滤,代码示例如下. //生产者 public class Producer {public static void main(String[] args) throws Exception{DefaultMQProducer producer new DefaultMQProducer(…

LLM - Chinese-Llama-2-7b 初体验

目录 一.引言 二.模型下载 三.快速测试 四.训练数据 五.总结 一.引言 自打 LLama-2 发布后就一直在等大佬们发布 LLama-2 的适配中文版,也是这几天蹲到了一版由 LinkSoul 发布的 Chinese-Llama-2-7b,其共发布了一个常规版本和一个 4-bit 的量化版本…

Linux命令行宝典:随时查询、轻松应对

🕺作者: 迷茫的启明星 学习路线C语言从0到1C初阶数据结构从0到1 😘欢迎关注:👍点赞🙌收藏✍️留言 🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要&…

Ama no Jaku

登录—专业IT笔试面试备考平台_牛客网 题目大意&#xff1a;有一个n*n且仅由0和1构成的矩阵&#xff0c;每次操作可以将一整行或一整列的所有数取反&#xff0c;问能否使所有行中构成的最小数>所有列中构成的最大数 1<n<2000 思路&#xff1a;首先&#xff0c;如果…

H2TEST自动化测试

ref&#xff1a; GitHub - kunyi0605/H2testwpywinauto实战-操作h2testw.exe自动化测试脚本_肤白貌美的博客-CSDN博客 https://www.cnblogs.com/qican/p/15038067.html

Flink CEP (一)原理及概念

目录 1.Flink CEP 原理 2.Flink API开发 2.1 模式 pattern 2.2 模式 pattern属性 2.3 模式间的关系 1.Flink CEP 原理 Flink CEP内部是用NFA&#xff08;非确定有限自动机&#xff09;来实现的&#xff0c;由点和边组成的一个状态图&#xff0c;以一个初始状态作为起点&am…

文件共享服务器(五)sicis

目录 前言 一、概述 1.iscsi概念 2.iscsi介绍 3.相关名词 二、实验 1.构建iscsi服务 2.实现步骤 服务器端 客户端 3.注意事项 总结 前言 iSCSI是由IBM发明的基于以太网的存储协议&#xff0c;该协议与SUN的NFS协议都是为了解决存储资源共享问题的解决方案。两者意图…

git rebase -i

git rebase -i 是一种交互式的 rebase 方式&#xff0c;其中 -i 是 --interactive 的简写。这种方式允许你修改一系列的 commit 信息&#xff0c;在 rebase 过程中有选择地选择、编辑或者合并 commit。 在执行 git rebase -i 命令时&#xff0c;你需要提供一个参数&#xff0c…

音视频——封装格式原理

视频解码基础 一、封裝格式 ​ 我们播放的视频文件一般都是用一种封装格式封装起来的&#xff0c;封装格式的作用是什么呢&#xff1f;一般视频文件里不光有视频&#xff0c;还有音频&#xff0c;封装格式的作用就是把视频和音频打包起来。 所以我们先要解封装格式&#xff0…

集成学习Boosting - AdaBoost

目录 1. Boosting方法的基本思想 1.1 Bagging VS Boosting 1.2 Boosting算法的基本元素与基本流程 1.3 sklearn中的Boosting算法 2. AdaBoost 3 AdaBoost的基本参数与损失函数 3.1 参数 base_estimator&#xff0c;属性base_estimator_与estimators_ 3.1. 参数 learnin…

vue之vue-pboc组件

功能描述 PBOC业务页面基类组件,提供多个PBOC操作方法,,它的父级组件为vue-base #方法 查询电子现金余额及电子现金上限 queryElecBalance(); 查询电子现金明细 queryElecDetail(); pboc初始化过程接口 initDeviceInfo: function initDeviceInfo( appid, acctype, tranty…

用QFramework来重构 祖玛游戏

资料 Unity - 祖玛游戏 GitHub 说明 用QF一个场景就够了&#xff0c;在UIRoot下切换预制体达到面板切换。 但测试中当然要有一个直接跳到测试面板的 测试脚本&#xff0c;保留测试Scene&#xff08;不然初学者也不知道怎么恢复测试Scene&#xff09;&#xff0c;所以全文按S…

宋浩线性代数笔记(二)矩阵及其性质

更新线性代数第二章——矩阵&#xff0c;本章为线代学科最核心的一章&#xff0c;知识点多而杂碎&#xff0c;务必仔细学习。 重难点在于&#xff1a; 1.矩阵的乘法运算 2.逆矩阵、伴随矩阵的求解 3.矩阵的初等变换 4.矩阵的秩 &#xff08;去年写的字&#xff0c;属实有点ugl…

多态及其原理

文章目录 构成多态的条件虚函数作用&#xff1a;完成重写 重写重载 重写 隐藏为什么析构函数要搞成符合多态?原理预热对于基类指针或引用指向父类或者子类的成员函数是如何调用不同的函数呢&#xff1f; 一个类如果是基类&#xff0c;它的析构函数最好加上virtual 构成多态的条…

E: 有几个软件包无法下载 有未能满足的依赖关系 解决办法

E: 有几个软件包无法下载 有未能满足的依赖关系 解决办法 今天sudo apt install ros-noetic-desktop-full安装ros突然遇到了一些问题&#xff0c;记录一下 E: 无法下载 http://cn.archive.ubuntu.com/ubuntu/pool/universe/s/simbody/libsimbody-dev_3.6.1dfsg-7build1_amd64…

python 小案例33

下面是一个简单的示例代码&#xff0c;展示了如何使用Django来创建一个股票管理分析系统。 首先&#xff0c;在你的虚拟环境中安装Django&#xff1a; pip install Django 然后&#xff0c;创建一个新的Django项目&#xff1a; django-admin startproject stock_management 进入…

AlSD 系列智能安全配电装置是安科瑞电气有限公司专门为低压配电侧开发的一款智能安全用电产 品-安科瑞黄安南

一、应用背景 电力作为一种清洁能源&#xff0c;给人们带来了舒适、便捷的电气化生活。与此同时&#xff0c;由于使用不当&#xff0c;维护 不及时等原因引发的漏电触电和电气火灾事故&#xff0c;也给人们的生命和财产带来了巨大的威胁和损失。 为了防止低压配电系统发生漏…

2022 China Open Source Report

| 翻译&#xff1a;黄绍雅、岳扬、刘文涛、李思颖 | 编辑&#xff1a;胡欣元 | 设计&#xff1a;胡欣元 As 2022 finally came to an end, we also emerged from the challenging years of the three-year-long COVID pandemic. The new edition of the "China Open Sourc…

06.计算机网络——IP协议

文章目录 网络层IP协议基本概念协议头格式如何解包如何交付网段划分子网掩码特殊的IP地址IP地址的数量限制私有IP地址和公网IP地址路由 网络层 IP协议 IP协议提供一种将数据从A主机送达到B主机的能力&#xff0c;进行网络层的通信。 ​ IP协议 基本概念 主机 —— 配有IP地址…

Spark 大厂面试题

土哥今天给大家分享10道spark大厂面试题: 1、spark概括说是解决什么问题的? Spark主要解决海量数据的分析计算。 2、spark运行模式有哪些? Local:运行在一台机器上,测试用Standalone:是Spark自身的一个调度系统。 对集群性能要求非常高时用。国内很少使用Yarn:采用Ha…