珠宝网站建设/适合35岁女人的培训班
详细说明 Event loop
众所周知 JS 是门非阻塞单线程语言,因为在最初 JS 就是为了和浏览器交互而诞生的。如果 JS 是门多线程的语言话,我们在多个线程中处理 DOM 就可能会发生问题(一个线程中新加节点,另一个线程中删除节点),当然可以引入读写锁解决这个问题。
JS 在执行的过程中会产生执行环境,这些执行环境会被顺序的加入到执行栈中。如果遇到异步的代码,会被挂起并加入到 Task(有多种 task) 队列中。一旦执行栈为空,Event Loop 就会从 Task 队列中拿出需要执行的代码并放入执行栈中执行,所以本质上来说 JS 中的异步还是同步行为。
console.log('script start');setTimeout(function() {console.log('setTimeout');
}, 0);console.log('script end');
以上代码虽然 setTimeout
延时为 0,其实还是异步。这是因为 HTML5 标准规定这个函数第二个参数不得小于 4 毫秒,不足会自动增加。所以 setTimeout
还是会在 script end
之后打印。
不同的任务源会被分配到不同的 Task 队列中,任务源可以分为 微任务(microtask) 和 宏任务(macrotask)。在 ES6 规范中,microtask 称为 jobs
,macrotask 称为 task
。
console.log('script start');setTimeout(function() {console.log('setTimeout');
}, 0);new Promise((resolve) => {console.log('Promise')resolve()
}).then(function() {console.log('promise1');
}).then(function() {console.log('promise2');
});console.log('script end');
// script start => Promise => script end => promise1 => promise2 => setTimeout
以上代码虽然 setTimeout
写在 Promise
之前,但是因为 Promise
属于微任务而 setTimeout
属于宏任务,所以会有以上的打印。
微任务包括 process.nextTick
,promise
,Object.observe
,MutationObserver
宏任务包括 script
, setTimeout
,setInterval
,setImmediate
,I/O
,UI rendering
很多人有个误区,认为微任务快于宏任务,其实是错误的。因为宏任务中包括了 script
,浏览器会先执行一个宏任务,接下来有异步代码的话就先执行微任务。
所以正确的一次 Event loop 顺序是这样的
- 执行同步代码,这属于宏任务
- 执行栈为空,查询是否有微任务需要执行
- 执行所有微任务
- 必要的话渲染 UI
- 然后开始下一轮 Event loop,执行宏任务中的异步代码
通过上述的 Event loop 顺序可知,如果宏任务中的异步代码有大量的计算并且需要操作 DOM 的话,为了更快的 界面响应,我们可以把操作 DOM 放入微任务中。
Node 中的 Event loop
Node 中的 Event loop 和浏览器中的不相同。
Node 的 Event loop 分为6个阶段,它们会按照顺序反复运行
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<──connections─── │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │└───────────────────────┘
timer
timers 阶段会执行 setTimeout
和 setInterval
一个 timer
指定的时间并不是准确时间,而是在达到这个时间后尽快执行回调,可能会因为系统正在执行别的事务而延迟。
下限的时间有一个范围:[1, 2147483647]
,如果设定的时间不在这个范围,将被设置为1。
I/O
I/O 阶段会执行除了 close 事件,定时器和 setImmediate
的回调
idle, prepare
idle, prepare 阶段内部实现
poll
poll 阶段很重要,这一阶段中,系统会做两件事情
- 执行到点的定时器
- 执行 poll 队列中的事件
并且当 poll 中没有定时器的情况下,会发现以下两件事情
- 如果 poll 队列不为空,会遍历回调队列并同步执行,直到队列为空或者系统限制
- 如果 poll 队列为空,会有两件事发生
- 如果有
setImmediate
需要执行,poll 阶段会停止并且进入到 check 阶段执行setImmediate
- 如果没有
setImmediate
需要执行,会等待回调被加入到队列中并立即执行回调
- 如果有
如果有别的定时器需要被执行,会回到 timer 阶段执行回调。
check
check 阶段执行 setImmediate
close callbacks
close callbacks 阶段执行 close 事件
并且在 Node 中,有些情况下的定时器执行顺序是随机的
setTimeout(() => {console.log('setTimeout');
}, 0);
setImmediate(() => {console.log('setImmediate');
})
// 这里可能会输出 setTimeout,setImmediate
// 可能也会相反的输出,这取决于性能
// 因为可能进入 event loop 用了不到 1 毫秒,这时候会执行 setImmediate
// 否则会执行 setTimeout
当然在这种情况下,执行顺序是相同的
var fs = require('fs')fs.readFile(__filename, () => {setTimeout(() => {console.log('timeout');}, 0);setImmediate(() => {console.log('immediate');});
});
// 因为 readFile 的回调在 poll 中执行
// 发现有 setImmediate ,所以会立即跳到 check 阶段执行回调
// 再去 timer 阶段执行 setTimeout
// 所以以上输出一定是 setImmediate,setTimeout
上面介绍的都是 macrotask 的执行情况,microtask 会在以上每个阶段完成后立即执行。
setTimeout(()=>{console.log('timer1')Promise.resolve().then(function() {console.log('promise1')})
}, 0)setTimeout(()=>{console.log('timer2')Promise.resolve().then(function() {console.log('promise2')})
}, 0)// 以上代码在浏览器和 node 中打印情况是不同的
// 浏览器中打印 timer1, promise1, timer2, promise2
// node 中打印 timer1, timer2, promise1, promise2
Node 中的 process.nextTick
会先于其他 microtask 执行。
setTimeout(() => {console.log("timer1");Promise.resolve().then(function() {console.log("promise1");});
}, 0);process.nextTick(() => {console.log("nextTick");
});
// nextTick, timer1, promise1
文档声明(Doctype)和<!Doctype html>
有何作用? 严格模式与混杂模式如何区分?它们有何意义?
文档声明的作用: 文档声明是为了告诉浏览器,当前HTML
文档使用什么版本的HTML
来写的,这样浏览器才能按照声明的版本来正确的解析。
的作用:<!doctype html>
的作用就是让浏览器进入标准模式,使用最新的 HTML5
标准来解析渲染页面;如果不写,浏览器就会进入混杂模式,我们需要避免此类情况发生。
严格模式与混杂模式的区分:
- 严格模式: 又称为标准模式,指浏览器按照
W3C
标准解析代码; - 混杂模式: 又称怪异模式、兼容模式,是指浏览器用自己的方式解析代码。混杂模式通常模拟老式浏览器的行为,以防止老站点无法工作;
区分:网页中的DTD
,直接影响到使用的是严格模式还是浏览模式,可以说DTD
的使用与这两种方式的区别息息相关。
- 如果文档包含严格的
DOCTYPE
,那么它一般以严格模式呈现(严格 DTD ——严格模式); - 包含过渡
DTD
和URI
的DOCTYPE
,也以严格模式呈现,但有过渡DTD
而没有URI
(统一资源标识符,就是声明最后的地址)会导致页面以混杂模式呈现(有 URI 的过渡 DTD ——严格模式;没有 URI 的过渡 DTD ——混杂模式); DOCTYPE
不存在或形式不正确会导致文档以混杂模式呈现(DTD不存在或者格式不正确——混杂模式);HTML5
没有DTD
,因此也就没有严格模式与混杂模式的区别,HTML5
有相对宽松的 法,实现时,已经尽可能大的实现了向后兼容(HTML5 没有严格和混杂之分)。
总之,严格模式让各个浏览器统一执行一套规范兼容模式保证了旧网站的正常运行。
如何解释 React 的渲染流程
- React 的渲染过程大致一致,但协调并不相同,以
React 16
为分界线,分为Stack Reconciler
和Fiber Reconciler
。这里的协调从狭义上来讲,特指 React 的 diff 算法,广义上来讲,有时候也指 React 的reconciler
模块,它通常包含了diff
算法和一些公共逻辑。 - 回到
Stack Reconciler
中,Stack Reconciler
的核心调度方式是递归
。调度的基本处理单位是事务
,它的事务基类是Transaction
,这里的事务是 React 团队从后端开发中加入的概念
。在 React 16 以前,挂载主要通过 ReactMount 模块完成
,更新通过ReactUpdate
模块完成,模块之间相互分离,落脚执行点也是事务。 - 在
React 16
及以后,协调改为了Fiber Reconciler
。它的调度方式主要有两个特点,第一个是协作式多任务模式
,在这个模式下,线程会定时放弃自己的运行权利,交还给主线程,通过requestIdleCallback
实现。第二个特点是策略优先级
,调度任务通过标记tag
的方式分优先级执行,比如动画,或者标记为high
的任务可以优先执行。Fiber Reconciler
的基本单位是Fiber
,Fiber
基于过去的React Element
提供了二次封装,提供了指向父、子、兄弟节点的引用,为diff
工作的双链表实现提供了基础。 - 在新的架构下,整个生命周期被划分为
Render 和 Commit 两个阶段
。Render 阶段的执行特点是可中断、可停止、无副作用
,主要是通过构造workInProgress
树计算出diff
。以current
树为基础,将每个Fiber
作为一个基本单位,自下而上逐个节点检查并构造 workInProgress 树。这个过程不再是递归,而是基于循环来完成 - 在执行上通过
requestIdleCallback
来调度执行每组任务,每组中的每个计算任务被称为work
,每个work
完成后确认是否有优先级更高的work
需要插入,如果有就让位,没有就继续。优先级通常是标记为动画或者high
的会先处理。每完成一组后,将调度权交回主线程,直到下一次requestIdleCallback
调用,再继续构建workInProgress
树 - 在
commit
阶段需要处理effect
列表,这里的effect
列表包含了根据diff 更新 DOM 树
、回调生命周期
、响应 ref
等。 - 但一定要注意,这个阶段是同步执行的,不可中断暂停,所以不要在
componentDidMount
、componentDidUpdate
、componentWiilUnmount
中去执行重度消耗算力的任务 - 如果只是一般的应用场景,比如管理后台、H5 展示页等,两者性能差距并不大,但在动画、画布及手势等场景下,
Stack Reconciler
的设计会占用占主线程,造成卡顿,而fiber reconciler
的设计则能带来高性能的表现
箭头函数的this指向哪⾥?
箭头函数不同于传统JavaScript中的函数,箭头函数并没有属于⾃⼰的this,它所谓的this是捕获其所在上下⽂的 this 值,作为⾃⼰的 this 值,并且由于没有属于⾃⼰的this,所以是不会被new调⽤的,这个所谓的this也不会被改变。
可以⽤Babel理解⼀下箭头函数:
// ES6
const obj = { getArrow() { return () => { console.log(this === obj); }; }
}
转化后:
// ES5,由 Babel 转译
var obj = { getArrow: function getArrow() { var _this = this; return function () { console.log(_this === obj); }; }
};
响应式设计的概念及基本原理
响应式网站设计(Responsive Web design
)是一个网站能够兼容多个终端,而不是为每一个终端做一个特定的版本。
关于原理: 基本原理是通过媒体查询(@media)
查询检测不同的设备屏幕尺寸做处理。
关于兼容: 页面头部必须有mate声明的viewport
。
<meta name="’viewport’" content="”width=device-width," initial-scale="1." maximum-scale="1,user-scalable=no”"/>
typeof null 的结果是什么,为什么?
typeof null 的结果是Object。
在 JavaScript 第一个版本中,所有值都存储在 32 位的单元中,每个单元包含一个小的 类型标签(1-3 bits) 以及当前要存储值的真实数据。类型标签存储在每个单元的低位中,共有五种数据类型:
000: object - 当前存储的数据指向一个对象。1: int - 当前存储的数据是一个 31 位的有符号整数。
010: double - 当前存储的数据指向一个双精度的浮点数。
100: string - 当前存储的数据指向一个字符串。
110: boolean - 当前存储的数据是布尔值。
如果最低位是 1,则类型标签标志位的长度只有一位;如果最低位是 0,则类型标签标志位的长度占三位,为存储其他四种数据类型提供了额外两个 bit 的长度。
有两种特殊数据类型:
- undefined的值是 (-2)30(一个超出整数范围的数字);
- null 的值是机器码 NULL 指针(null 指针的值全是 0)
那也就是说null的类型标签也是000,和Object的类型标签一样,所以会被判定为Object。
参考 前端进阶面试题详细解答
对Flex布局的理解及其使用场景
Flex是FlexibleBox的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为Flex布局。行内元素也可以使用Flex布局。注意,设为Flex布局以后,子元素的float、clear和vertical-align属性将失效。采用Flex布局的元素,称为Flex容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为Flex项目(flex item),简称"项目"。容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis),项目默认沿水平主轴排列。
以下6个属性设置在容器上:
- flex-direction属性决定主轴的方向(即项目的排列方向)。
- flex-wrap属性定义,如果一条轴线排不下,如何换行。
- flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。
- justify-content属性定义了项目在主轴上的对齐方式。
- align-items属性定义项目在交叉轴上如何对齐。
- align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
以下6个属性设置在项目上:
- order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。
- flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
- flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
- flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
- flex属性是flex-grow,flex-shrink和flex-basis的简写,默认值为0 1 auto。
- align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
简单来说: flex布局是CSS3新增的一种布局方式,可以通过将一个元素的display属性值设置为flex从而使它成为一个flex容器,它的所有子元素都会成为它的项目。一个容器默认有两条轴:一个是水平的主轴,一个是与主轴垂直的交叉轴。可以使用flex-direction来指定主轴的方向。可以使用justify-content来指定元素在主轴上的排列方式,使用align-items来指定元素在交叉轴上的排列方式。还可以使用flex-wrap来规定当一行排列不下时的换行方式。对于容器中的项目,可以使用order属性来指定项目的排列顺序,还可以使用flex-grow来指定当排列空间有剩余的时候,项目的放大比例,还可以使用flex-shrink来指定当排列空间不足时,项目的缩小比例。
如何获得对象非原型链上的属性?
使用后hasOwnProperty()
方法来判断属性是否属于原型链的属性:
function iterate(obj){var res=[];for(var key in obj){if(obj.hasOwnProperty(key))res.push(key+': '+obj[key]);}return res;
}
Proxy 可以实现什么功能?
在 Vue3.0 中通过 Proxy
来替换原本的 Object.defineProperty
来实现数据响应式。
Proxy 是 ES6 中新增的功能,它可以用来自定义对象中的操作。
let p = new Proxy(target, handler)
target
代表需要添加代理的对象,handler
用来自定义对象中的操作,比如可以用来自定义 set
或者 get
函数。
下面来通过 Proxy
来实现一个数据响应式:
let onWatch = (obj, setBind, getLogger) => {let handler = {get(target, property, receiver) {getLogger(target, property)return Reflect.get(target, property, receiver)},set(target, property, value, receiver) {setBind(value, property)return Reflect.set(target, property, value)}}return new Proxy(obj, handler)
}
let obj = { a: 1 }
let p = onWatch(obj,(v, property) => {console.log(`监听到属性${property}改变为${v}`)},(target, property) => {console.log(`'${property}' = ${target[property]}`)}
)
p.a = 2 // 监听到属性a改变
p.a // 'a' = 2
在上述代码中,通过自定义 set
和 get
函数的方式,在原本的逻辑中插入了我们的函数逻辑,实现了在对对象任何属性进行读写时发出通知。
当然这是简单版的响应式实现,如果需要实现一个 Vue 中的响应式,需要在 get
中收集依赖,在 set
派发更新,之所以 Vue3.0 要使用 Proxy
替换原本的 API 原因在于 Proxy
无需一层层递归为每个属性添加代理,一次即可完成以上操作,性能上更好,并且原本的实现有一些数据更新不能监听到,但是 Proxy
可以完美监听到任何方式的数据改变,唯一缺陷就是浏览器的兼容性不好。
渐进增强和优雅降级之间的区别
(1)渐进增强(progressive enhancement):主要是针对低版本的浏览器进行页面重构,保证基本的功能情况下,再针对高级浏览器进行效果、交互等方面的改进和追加功能,以达到更好的用户体验。 (2)优雅降级 graceful degradation: 一开始就构建完整的功能,然后再针对低版本的浏览器进行兼容。
两者区别:
- 优雅降级是从复杂的现状开始的,并试图减少用户体验的供给;而渐进增强是从一个非常基础的,能够起作用的版本开始的,并在此基础上不断扩充,以适应未来环境的需要;
- 降级(功能衰竭)意味着往回看,而渐进增强则意味着往前看,同时保证其根基处于安全地带。
“优雅降级”观点认为应该针对那些最高级、最完善的浏览器来设计网站。而将那些被认为“过时”或有功能缺失的浏览器下的测试工作安排在开发周期的最后阶段,并把测试对象限定为主流浏览器(如 IE、Mozilla 等)的前一个版本。 在这种设计范例下,旧版的浏览器被认为仅能提供“简陋却无妨 (poor, but passable)” 的浏览体验。可以做一些小的调整来适应某个特定的浏览器。但由于它们并非我们所关注的焦点,因此除了修复较大的错误之外,其它的差异将被直接忽略。
“渐进增强”观点则认为应关注于内容本身。内容是建立网站的诱因,有的网站展示它,有的则收集它,有的寻求,有的操作,还有的网站甚至会包含以上的种种,但相同点是它们全都涉及到内容。这使得“渐进增强”成为一种更为合理的设计范例。这也是它立即被 Yahoo 所采纳并用以构建其“分级式浏览器支持 (Graded Browser Support)”策略的原因所在。
head 标签有什么作用,其中什么标签必不可少?
标签用于定义文档的头部,它是所有头部元素的容器。 中的元素可以引用脚本、指示浏览器在哪里找到样式表、提供元信息等。
文档的头部描述了文档的各种属性和信息,包括文档的标题、在 Web 中的位置以及和其他文档的关系等。绝大多数文档头部包含的数据都不会真正作为内容显示给读者。
下面这些标签可用在 head 部分:<base>, <link>, <meta>, <script>, <style>, <title>
。
其中 <title>
定义文档的标题,它是 head 部分中唯一必需的元素。
null和undefined区别
首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。
undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。
undefined 在 JavaScript 中不是一个保留字,这意味着可以使用 undefined 来作为一个变量名,但是这样的做法是非常危险的,它会影响对 undefined 值的判断。我们可以通过一些方法获得安全的 undefined 值,比如说 void 0。
当对这两种类型使用 typeof 进行判断时,Null 类型化会返回 “object”,这是一个历史遗留的问题。当使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回 false。
异步编程的实现方式?
JavaScript中的异步机制可以分为以下几种:
- 回调函数 的方式,使用回调函数的方式有一个缺点是,多个回调函数嵌套的时候会造成回调函数地狱,上下两层的回调函数间的代码耦合度太高,不利于代码的可维护。
- Promise 的方式,使用 Promise 的方式可以将嵌套的回调函数作为链式调用。但是使用这种方法,有时会造成多个 then 的链式调用,可能会造成代码的语义不够明确。
- generator 的方式,它可以在函数的执行过程中,将函数的执行权转移出去,在函数外部还可以将执行权转移回来。当遇到异步函数执行的时候,将函数执行权转移出去,当异步函数执行完毕时再将执行权给转移回来。因此在 generator 内部对于异步操作的方式,可以以同步的顺序来书写。使用这种方式需要考虑的问题是何时将函数的控制权转移回来,因此需要有一个自动执行 generator 的机制,比如说 co 模块等方式来实现 generator 的自动执行。
- async 函数 的方式,async 函数是 generator 和 promise 实现的一个自动执行的语法糖,它内部自带执行器,当函数内部执行到一个 await 语句的时候,如果语句返回一个 promise 对象,那么函数将会等待 promise 对象的状态变为 resolve 后再继续向下执行。因此可以将异步逻辑,转化为同步的顺序来书写,并且这个函数可以自动执行。
实现一个三角形
CSS绘制三角形主要用到的是border属性,也就是边框。
平时在给盒子设置边框时,往往都设置很窄,就可能误以为边框是由矩形组成的。实际上,border属性是右三角形组成的,下面看一个例子:
div {width: 0;height: 0;border: 100px solid;border-color: orange blue red green;
}
将元素的长宽都设置为0
(1)三角1
div { width: 0; height: 0; border-top: 50px solid red; border-right: 50px solid transparent; border-left: 50px solid transparent;}
(2)三角2
div {width: 0;height: 0;border-bottom: 50px solid red;border-right: 50px solid transparent;border-left: 50px solid transparent;
}
(3)三角3
div {width: 0;height: 0;border-left: 50px solid red;border-top: 50px solid transparent;border-bottom: 50px solid transparent;
}
(4)三角4
div {width: 0;height: 0;border-right: 50px solid red;border-top: 50px solid transparent;border-bottom: 50px solid transparent;
}
(5)三角5
div {width: 0;height: 0;border-top: 100px solid red;border-right: 100px solid transparent;
}
还有很多,就不一一实现了,总体的原则就是通过上下左右边框来控制三角形的方向,用边框的宽度比来控制三角形的角度。
Object.is() 与比较操作符 “=”、“” 的区别?
- 使用双等号(==)进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。
- 使用三等号(===)进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。
- 使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 是相等的。
解释性语言和编译型语言的区别
(1)解释型语言
使用专门的解释器对源程序逐行解释成特定平台的机器码并立即执行。是代码在执行时才被解释器一行行动态翻译和执行,而不是在执行之前就完成翻译。解释型语言不需要事先编译,其直接将源代码解释成机器码并立即执行,所以只要某一平台提供了相应的解释器即可运行该程序。其特点总结如下
- 解释型语言每次运行都需要将源代码解释称机器码并执行,效率较低;
- 只要平台提供相应的解释器,就可以运行源代码,所以可以方便源程序移植;
- JavaScript、Python等属于解释型语言。
(2)编译型语言
使用专门的编译器,针对特定的平台,将高级语言源代码一次性的编译成可被该平台硬件执行的机器码,并包装成该平台所能识别的可执行性程序的格式。在编译型语言写的程序执行之前,需要一个专门的编译过程,把源代码编译成机器语言的文件,如exe格式的文件,以后要再运行时,直接使用编译结果即可,如直接运行exe文件。因为只需编译一次,以后运行时不需要编译,所以编译型语言执行效率高。其特点总结如下:
- 一次性的编译成平台相关的机器语言文件,运行时脱离开发环境,运行效率高;
- 与特定平台相关,一般无法移植到其他平台;
- C、C++等属于编译型语言。
两者主要区别在于: 前者源程序编译后即可在该平台运行,后者是在运行期间才编译。所以前者运行速度快,后者跨平台性好。
Promise.allSettled
描述:等到所有promise
都返回结果,就返回一个promise
实例。
实现:
Promise.allSettled = function(promises) {return new Promise((resolve, reject) => {if(Array.isArray(promises)) {if(promises.length === 0) return resolve(promises);let result = [];let count = 0;promises.forEach((item, index) => {Promise.resolve(item).then(value => {count++;result[index] = {status: 'fulfilled',value: value};if(count === promises.length) resolve(result);}, reason => {count++;result[index] = {status: 'rejected'.reason: reason};if(count === promises.length) resolve(result);});});}else return reject(new TypeError("Argument is not iterable"));});
}
说一下数组如何去重,你有几种方法?
let arr = [1,1,"1","1",true,true,"true",{},{},"{}",null,null,undefined,undefined]// 方法1
let uniqueOne = Array.from(new Set(arr)) console.log(uniqueOne)// 方法2
let uniqueTwo = arr => {let map = new Map(); //或者用空对象 let obj = {} 利用对象属性不能重复得特性let brr = []arr.forEach( item => {if(!map.has(item)) { //如果是对象得话就判断 !obj[item]map.set(item,true) //如果是对象得话就obj[item] =true 其他一样brr.push(item)}})return brr
}
console.log(uniqueTwo(arr))//方法3
let uniqueThree = arr => {let brr = []arr.forEach(item => {// 使用indexOf 返回数组是否包含某个值 没有就返回-1 有就返回下标if(brr.indexOf(item) === -1) brr.push(item)// 或者使用includes 返回数组是否包含某个值 没有就返回false 有就返回trueif(!brr.includes(item)) brr.push(item)})return brr
}
console.log(uniqueThree(arr))//方法4
let uniqueFour = arr => { // 使用 filter 返回符合条件的集合let brr = arr.filter((item,index) => {return arr.indexOf(item) === index})return brr
}
console.log(uniqueFour(arr))
POST和PUT请求的区别
- PUT请求是向服务器端发送数据,从而修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同。(可以理解为时更新数据)
- POST请求是向服务器端发送数据,该请求会改变数据的种类等资源,它会创建新的内容。(可以理解为是创建数据)
use strict是什么意思 ? 使用它区别是什么?
use strict 是一种 ECMAscript5 添加的(严格模式)运行模式,这种模式使得 Javascript 在更严格的条件下运行。设立严格模式的目的如下:
- 消除 Javascript 语法的不合理、不严谨之处,减少怪异行为;
- 消除代码运行的不安全之处,保证代码运行的安全;
- 提高编译器效率,增加运行速度;
- 为未来新版本的 Javascript 做好铺垫。
区别:
- 禁止使用 with 语句。
- 禁止 this 关键字指向全局对象。
- 对象不能有重名的属性。
相关文章:

高级前端一面面试题集锦
详细说明 Event loop 众所周知 JS 是门非阻塞单线程语言,因为在最初 JS 就是为了和浏览器交互而诞生的。如果 JS 是门多线程的语言话,我们在多个线程中处理 DOM 就可能会发生问题(一个线程中新加节点,另一个线程中删除节点&#…...

Java基础 -- List集合
Java基础 -- List集合1. Introduction1.1 好处1.2 常用泛型2. 交集,差集等2.1 自身的方法2.2 1.8jdk stream 新特性2.3 Apache的CollectionUtils工具类(推荐)3. 限定泛型范围4. Awakening1. Introduction 1.1 好处 代码复用,多种…...

【Linux】网络编程 - Socket套接字/基于UDP的网络通信
目录 一.套接字 1.什么是套接字/Socket套接字 2.套接字的分类 3.Socket套接字的常见API 二.网络字节序 1.什么是网络字节序 2.网络字节序和主机字节序的转换接口 三.IP地址形式上的转换 四.客户端的套接字不由程序员bind 1.为什么客户端套接字不能由程序员bind 2.OS…...

流程引擎之Camunda简介
背景Camunda 是支持 BPMN(工作流和流程自动化)、CMMN(案例管理) 和 DMN(业务决策管理) java 框架。Camunda 基于Activiti5 保留了 PVM,其开发团队也是从 activiti 中分裂出来的。Camunda 来自拉…...

Mybatis笔记整理
1. 相关文档地址 中文文档 https://mybatis.org/mybatis-3/zh/index.htmlMybatis可以配置成适应多种环境,不过每个SqlSessionFactory实例只能选择一种环境。Mybatis默认事务管理器是JDBC,连接池:POOLEDMaven仓库:下载地址<dependency>…...

【react全家桶】面向组件编程
文章目录02 【面向组件编程】1.组件的使用1.1 函数式组件1.2 类式组件1.3 组合组件1.4 提取组件组件实例的三大属性 state props refs2.state2.1 基本使用2.2 setState()2.3 简化版本2.4 State 的更新可能是异步的2.5 异步更新解决方案2.6 数据是向下流动的3.props3.1 基本使用…...

Django框架之模型视图-使用 PostMan 对请求进行测试
使用 PostMan 对请求进行测试 PostMan 是一款功能强大的网页调试与发送网页 HTTP 请求的 Chrome 插件,可以直接去对我们写出来的路由和视图函数进行调试,作为后端程序员是必须要知道的一个工具。 安装方式1:去 Chrome 商店直接搜索 PostMan…...

(考研湖科大教书匠计算机网络)第五章传输层-第四节:TCP流量控制
获取pdf:密码7281专栏目录首页:【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一:流量控制概述二:流量控制举例三:拓展阅读(可不看)(1)TCP流量控制完整例子&a…...

使用Docker-Compose搭建Redis集群
1. 集群配置3主3从由于仅用于测试,故我这里只用1台服务器进行模拟redis列表2.编写redis.conf在server上创建一个目录用于存放redis集群部署文件。这里我放的路径为/root/redis-cluster 在/opt/docker/redis-cluster目录下创建redis-1,redis-2,redis-3,redis-4,redis…...

华为OD机试 -计算网络信号(Js)
计算网络信号 题目 网络信号经过传递会逐层衰减,且遇到阻隔物无法直接穿透,在此情况下需要计算某个位置的网络信号值。 注意:网络信号可以绕过阻隔物 array[m][n] 的二维数组代表网格地图,array[i][j] = 0代表 i 行 j 列是空旷位置;array[i][j] = x(x 为正整数)代表 i 行 …...

【数据结构】————栈
文章目录前言栈是什么,栈的特点实现栈的基本操作栈的相关操作声明1.创建栈2.对栈进行初始化3.销毁栈4.判断栈是否为空5.压栈操作6.删除栈顶元素7.取出栈顶元素8.计算栈内存放多少个数据总结前言 本文主要讲述特殊的线性表——栈: 栈是什么,栈…...

从零编写linux0.11 - 第十一章 可执行文件
从零编写linux0.11 - 第十一章 可执行文件 编程环境:Ubuntu 20.04、gcc-9.4.0 代码仓库:https://gitee.com/AprilSloan/linux0.11-project linux0.11源码下载(不能直接编译,需进行修改) 本章目标 本章会加载并运行…...

Win10上通过nginx代理配置远程非445端口SMB
引言 家里架了一个SMB文件服务器,想要远程访问,开了445端口,但仅限某些特殊网络可以远程访问,其他网络全部拒绝445端口,因此网上找了很多将Win10的SMB指向别的端口的教程,但所有教程均使用环回网卡解决&am…...

Allegro如何快速清除多余的规则设置操作指导
Allegro如何快速清除多余的规则设置操作指导 在用Allegro做PCB设计的时候,会给PCB设置一些规则,在PCB设计完成之后,可能会有一些没有使用到的规则,如下图 Physical规则中的45OHM的规则是多余的 单独某个规则可以直接在规则管理器中删除,如果比较多可以用下面方法批量删除…...

ROS2 入门应用 引用自定义消息(Python)
ROS2 入门应用 引用自定义消息(Python)1. 查看自定义消息2. 修改话题发布3. 修改话题订阅4. 修改依赖关系5. 编译和运行1. 查看自定义消息 引用在《ROS2 入门应用 创建自定义接口》中自定义的消息Sphere.msg ros2 interface show tutorial_interfaces/…...

SmS-Activate一款好用的短信验证码接收工具
前言 有些国外应用在使用应用上的功能时需要注册账号,由于某种不可抗因素,我们的手机号一般不支持注册,接收不到信息验证码,于是我们可以使用SmS-Activate提供的服务,使用$实现我们的需求(大概一次验证1-5…...

SpringBoot+Elasticsearch按日期实现动态创建索引(分表)
😊 作者: 一恍过去💖 主页: https://blog.csdn.net/zhuocailing3390🎊 社区: Java技术栈交流🎉 主题: SpringBootElasticsearch按日期实现动态创建索引(分表)⏱️ 创作时间&…...

Terraform基础入门 (Infrastructure as Code)
文章目录前言介绍Terraform 术语Terraform 如何工作关于provider安装开启本地缓存demo1(dockernginx)demo2(dockerzookeeperkafka)参考资料前言 像写代码一样管理基础设施。 Terraform 使用较为高级的配置文件语法来描述基础设施,这个特性让你对配置文件进行版本化…...

Redis内存回收
Redis 内存回收 Redis之所以性能很强,最主要的原因是基于内存存储,然而单节点的Redis其内存大小不宜过大,会影响持久化或主从同步性能 可以通过修改配置文件来设置Redis的最大内存 maxmemory <bytes>当内存达到上限时,就…...

ROS2 入门应用 引用自定义消息(C++)
ROS2 入门应用 引用自定义消息(C)1. 查看自定义消息2. 修改话题发布3. 修改话题订阅4. 修改依赖关系5. 修改编译信息6. 编译和运行1. 查看自定义消息 引用在《ROS2 入门应用 创建自定义接口》中自定义的消息Sphere.msg ros2 interface show tutorial_i…...

Spring中的数据校验
数据校验基础 参考: Java Bean Validation 规范 Spring对Bean Validation的支持 Spring定义了一个接口org.springframework.validation.Validator,用于应用相关的对象的校验器。 这个接口完全从基础设施或者上下文中脱离的,这意味着它没有…...

python批量翻译excel表格中的英文
python批量翻译excel表格中的英文需求背景主要设计分析具体实现表格操作请求百度翻译api多线程控制台显示进度完整源码需求背景 女朋友的论文需要爬取YouTube视频热评,但爬下来的都是外文。 主要设计 读取一个表格文件,获取需要翻译的文本 使用百度翻译…...

基于SSM框架的RBAC权限系统设计与 实现
基于SSM框架的RBAC权限系统设计与 实现 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背景…...

目标检测各常见评价指标详解
注:本文仅供学习,未经同意请勿转载 说明:该博客来源于xiaobai_Ry:2020年3月笔记 对应的PDF下载链接在:待上传 目录 常见的评价指标 准确率 (Accuracy) 混淆矩阵 (Confusion Matrixÿ…...

深入讲解Kubernetes架构-控制器
在机器人技术和自动化领域,控制回路(Control Loop)是一个非终止回路,用于调节系统状态。这是一个控制环的例子:房间里的温度自动调节器。当你设置了温度,告诉了温度自动调节器你的期望状态(Desi…...

Urho3D本地化 国际化
本地化子系统提供了创建多语言应用程序的简单方法。 初始化 在使用子系统之前,需要加载本地化字符串集合。通常的做法是在应用程序启动时执行此操作。可以加载多个集合文件,每个集合文件只能定义一种或多种语言。例如: Localization* l10n…...

千锋教育嵌入式物联网教程之系统编程篇学习-04
目录 alarm函数 raise函数 abort函数 pause函数 转折点 signal函数 可重入函数 信号集 sigemptyset() sigfillset sigismember() sigaddset() sigdelset() 代码讲解 信号阻塞集 sigprocmask() alarm函数 相当于一个闹钟,默认动作是终止调用alarm函数的进…...

【运维】什么是 DevOps?
文章目录什么是 DevOps?如何实现 DevOpsDevOps工作原理: DevOps生命周期DevOps 文化DevOps 工具:构建 DevOps 工具链DevOps 和云原生开发什么是 DevSecOps?DevOps 和站点可靠性工程 (SRE)什么是 DevOps? DevOps 通过结…...

【C++入门】引用、内联函数、auto关键字、基于范围的for循环(C++11)、指针空值nullptr(C++11)
文章目录引用引用概念引用特性引用使用场景常引用内联函数宏的优缺点?C有哪些技术替代宏?auto关键字auto不能推导的场景基于范围的for循环(C11)指针空值nullptr(C11)引用 引用概念 引用不是新定义一个变量,而是给已存在变量取了一个别名&…...

《FPGA学习》->多个按键控制LED灯
🍎与其担心未来,不如现在好好努力。在这条路上,只有奋斗才能给你安全感。你若努力,全世界都会为你让路。本次项目任务,利用开发板上的4个按键KEY1,KEY2,KEY3,KEY4和2个LED灯LED1&…...