jS中几种常见的类型判断方法****
- 基本数据类型:string,number,boolean,null,undefinded,bigint,symbol
- 引用数据类型:对象,函数,数组,日期
- Typeof 判断原始数据类型
- Instanceof 来判断引用数据类型
- Object.prototype.toString.call(this) 判断所有类型
- 判断数组 Array.isArray()
==和===
==(宽松相等):会在比较两个操作数时执行 类型转换,尝试将两者转换为相同类型后再比较。 ===(严格相等):不会执行类型转换,仅在类型和值完全相同的情况下返回 true。 推荐使用 ===:因为它更严格、更符合预期,能避免潜在的错误。尤其是在需要精确判断值和类型时。
深拷贝和浅拷贝区别
浅拷贝,只拷贝了最外面的一层 ,只相当赋值给了 新的,新的改值,旧的值不会改变* 但是如果对象里面包对象,那么也只能拷贝最外面的一层,新的改值,旧的值也会改变!!!因为拷贝的还是地址,而不是对象****
- 深拷贝和浅拷贝只针对引用类型
- 浅拷贝:拷贝的是地址
- 深拷贝:拷贝的是对象,不是地址
数组实现浅拷贝:concat 【...arr】 slice()
对象实现浅拷贝:Object.assgin / ...展开运算 {。。。Obj}
深拷贝:Stringify lodash/clonedeep 递归实现深拷贝
变量提升
变量提升是 JavaScript 的一种机制,在该机制下,变量和函数的声明会被提升到当前作用域的顶部。这意味着,无论变量和函数在代码中实际声明的位置如何,它们都可以在声明之前被访问。
函数声明提升
函数声明会被完整提升,这意味着在函数声明之前就可以调用该函数。
// 可以在函数声明之前调用函数
sayHello();
function sayHello() {
console.log('Hello!');
}
变量声明提升
使用 var 声明的变量会被提升,但不会赋值,在变量声明之前访问该变量,其值为 undefined。
// 变量提升,输出 undefined
console.log(message);
var message = 'Hello, world!';
暂时性死区
暂时性死区是 ES6 引入 let 和 const 后出现的概念。使用 let 和 const 声明的变量不会像 var 那样被提升到作用域顶部并赋值为 undefined,而是存在于暂时性死区内。在变量声明之前访问这些变量会导致 ReferenceError。
/ 报错:ReferenceError
console.log(myVariable);
let myVariable = 'Hello';
在上面的代码中,myVariable 从块级作用域开始到它被声明之前都处于暂时性死区内。只有在声明之后,变量才能被正常访问
两者的区别
- 变量提升:使用
var声明的变量和函数声明会被提升到作用域顶部,函数可以在声明前调用,变量在声明前值为undefined。 - 暂时性死区:使用
let和const声明的变量不会被赋值为undefined,在声明之前访问会导致ReferenceError。
var、let、const区别
var没有块级作⽤域,只有函数作⽤域。var只有在function{ }内部才有作⽤域的概念,其他地⽅没有。意味着函数以外⽤var定义的变量是同⼀个,我们所有的修改都是针对他的
-
let和const增加块级作⽤域(JS没有块级作⽤域)
-
let和const存在暂时性死区,不存在变量提升,不能在初始化前引⽤,调⽤ 返回 uninitialized
-
let和const禁⽌重复声明,不能重新声明
-
let和const不会成为全局对象属性,var声明的变量⾃动成为全局对象属性
-
var 存在变量提升(执⾏前,编译器对代码预编译,当前作⽤域的变量/函数提升到作⽤域顶部),let约束变量提升。let和var都发⽣了变量提升,只是es6进⾏了约束,在我们看来,就像let禁⽌了变量提升
-
使⽤var,我们能对变量多次声明,后⾯声明的变量会覆盖前⾯的声明
WeakMap与Map的区别是什么
1. 什么是WeakMap
WeakMap 是 JavaScript 中的一种集合类型,它存储键值对,且键必须是对象,并且键是弱引用的。这意味着,如果键对象没有其他引用,它会被垃圾回收器回收,对应的键值对也会被自动删除。
2. 与Map的区别
键的类型
Map:键可以是任意类型,包括基本数据类型(像字符串、数字等)和引用类型(如对象、函数)。WeakMap:键只能是对象,不能使用基本数据类型作为键。
垃圾回收机制
Map:对键所引用的对象是强引用。只要Map存在,键引用的对象就不会被垃圾回收,即便其他地方无该对象的引用。WeakMap:对键所引用的对象是弱引用。若对象没有其他强引用,垃圾回收时对象会被回收,WeakMap里对应的键值对也会自动移除。
可遍历性
Map:是可迭代的,能使用for...of循环、forEach方法等遍历其键值对。WeakMap:不可迭代,没有keys()、values()、entries()这些迭代方法,也不能用for...of或forEach遍历。
方法和属性
Map:有size属性来获取键值对数量,还有set()、get()、has()、delete()、clear()等方法。WeakMap:只有set()、get()、has()、delete()方法,没有size属性和clear()方法。
使用场景
Map:适用于需存储任意类型键值对,且要对这些键值对进行遍历和操作的场景,如缓存数据。WeakMap:常用于避免内存泄漏的场景,例如给对象添加私有数据,当对象被销毁时,WeakMap里相关数据也会被清理。
This指向
// this指向的情况
-
函数调用模式 fn(),this 指向 window(默认绑定)
-
方法调用模式 obj.fn(),this 指向调用者(隐式绑定),虽然没有刻意的绑定,但是在执行时会自动将函数的 this 指向该对象。
-
上下文调用模式:想指向谁就指向谁(显式绑定/硬绑定)
// call, apply, bind
fn.call(this指向的内容, 参数1, 参数2, ...)
fn.apply(this指向的内容, [参数1, 参数2, ...])
const newFn = fn.bind(this指向的内容)
call apply bind 总结
- 相同点:都可以改变函数内部的this指向,
- 区别点:
- call 和 apply 会调用函数,并且改变函数内部this指向,
- call 和 apply 传递的参数不一样,call 传递参数 aru1, aru2..形式
- apply 必须数组形式[arg]bind 不会调用函数,可以改变函数内部this指向
- 主要应用场景:
- call 调用函数并且可以传递参数
- apply 经常跟数组有关系.比如借助于数学对象实现数组最大值最小值
- bind 不调用函数,但是还想改变this指向.比如改变定时器内部的this指向
闭包
闭包:内层函数+外层函数的变量
闭包的核心特性:
- 访问外部函数作用域的变量
- 即使外部函数执行结束,变量依然被保留
- 不会被垃圾回收,直到闭包不再被引用
闭包的应用场景:
- 私有变量(模拟封装)
function createcount(){
let count=0
return{
add:()=>++count }
}
const count=createcount()
count.add() // 1
count.count undefinded 外部无法直接访问
- 回调 & 事件监听
- 定时器 & 异步操作
闭包的缺点:
- 可能导致内存泄漏:
- 闭包会持有外部变量的引用,导致变量无法被垃圾回收
- 解决方案:手动将变量置为 null 或谨慎管理作用域
内存泄露
内存泄露是指在程序运行过程中,程序未能释放不再使用的内存空间,导致内存资源被浪费
JS 内存泄露的常见原因
l 意外的全局变量:忘记使用 var,let,const 声明变量时,变量会被挂载到全局对象上
l 闭包:闭包中引用了不再需要的外部变量,导致这些变量无法被垃圾回收
l 未清理的 DOM 引用:删除 DOM 元素时,未能清理相关的事件监听器或引用
l 定时器和回调:未能清理不再需要的 setInterval 或 setTimeout 回调
JS 作用域和作用域链
作用域:变量的可访问范围,分为 全局作用域、函数作用域、块级作用域。
作用域链:变量查找机制,从当前作用域 逐级向上查找,直到全局作用域或 ReferenceError。
原型和原型链
- 原型(Prototype)
每个 函数(构造函数)都有一个 prototype 属性,指向其 原型对象。
每个 对象 都有一个 proto 指向其构造函数的 prototype,形成继承关系。
- 原型链(Prototype Chain)
查找⼀个属性先在⾃身查找,如果找不到,就沿着 proto 属性在原型对象上进⾏查找,如果还找不到,就沿着原型对象的 proto 属性进⾏查找,直到查找到直到找到Object的原型对象,如果还没有找到就会返回undefined
Object.prototype.proto === null,原型链的顶端是 是 Object.prototype.proto
- 使⽤ hasOwnProperty() ⽅法来判断属性是否属于原型链的属性:
每个实例对象都有私有属性(proto)指向它构造函数的原型对象。
每个构造函数都有prototype原型对象
prototype原型对象的constructor指向构造函数本身
有默认constructor属性,记录实例由哪个构造函数创建
ES6新特性
-
const、let
-
模板字符串
-
箭头函数
-
函数参数默认值
-
解构赋值
-
for...of ⽤于数组,for...in⽤于对象
-
Promise
-
展开运算符(...)
-
对象字⾯量、class(原型链的语法糖)
箭头函数和普通函数区别
- 1.语法更加简洁,没有function =》
- 2.没有动态参数,但是有剩余参数
- 3.没有自己的this,会继承外层的this
- 4.不支持bind/apply/call
- 5.不能用作构造函数,没有prototype属性
js数组⽅法
- forEach map
- push pop shift unshift
- splice slice concat join
- sort reverse some every filter
### 改变原数组的方法
- `push`:把一个或多个元素添加到数组末尾,并且返回新的数组长度。
- `pop`:移除数组的最后一个元素,同时返回该元素。
- `shift`:移除数组的第一个元素,然后返回该元素。
- `unshift`:在数组开头添加一个或多个元素,并且返回新的数组长度。
- `splice`:从数组中添加或删除元素,然后返回被删除的元素组成的数组。
- `sort`:对数组的元素进行排序,并且返回排序后的数组。
- `reverse`:颠倒数组中元素的顺序,并且返回颠倒后的数组。
`map`、`slice`、`concat`、`join`、`some`、`every`、`filter` 这些方法不会改变原数组 会返回新数组
- `map`:创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
- `slice`:返回一个新的数组对象,这一对象是一个由 `begin` 和 `end` 决定的原数组的浅拷贝(包括 `begin`,不包括 `end`)。
`concat`:用于合并两个或多个数组,此方法不会更改现有数组,而是返回一个新数组
`join`:将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串
- `some`:测试数组中是不是至少有 1 个元素通过了被提供的函数测试,它返回的是一个布尔值。
`every`:测试一个数组内的所有元素是否都能通过某个指定函数的测试,它返回一个布尔值
- `filter`:创建一个新数组,其包含通过所提供函数实现的测试的所有元素。
防抖节流
- 防抖:单位时间内,频繁触发事件,只执行最后一次
- 使用场景:手机号,邮箱输入检测,用户最后一次输入完,再检测
- 节流:单位时间内,频繁触发事件,只执行一次
- 使用场景:鼠标移动,滚动条滚动
- 手撕:
- 防抖函数:声明定时器变量,判断是否有定时器,如果有,清除定时器,重新声明定时器,执行函数
- 节流函数:声明定时器变量为空,判断如果没有定时器,声明定时器,执行函数,定时器清空
- Lodash库的 防抖和节流函数 _.debounce _.throttle
如何理解 JS 单线程?
- js是一门单线程的语言。因为它运行在浏览器的渲染主线程中,而渲染主线程只有一个。
- 渲染主线程要执行很多任务,解析html,执行js等。
- 如果主线程采用同步的方式执行代码,可能会阻塞主线程的执行,导致消息队列中的其他任务无法执行。会浪费时间,以及导致页面无法及时更新卡死。
- 所以采用异步的方式去解决。当遇到一些异步的任务,渲染主线程将这些任务交给其他线程去处理,自身立即结束执行任务,执行后续代码。当其他线程完成,将事先传递的回调函数包装成任务,放入消息队列的末尾,等待主线程的调度执行。
- 在这种异步模式下,浏览器就不会阻塞,单线程也可以流畅运行
js的异步理解
- js是一门单线程的语言。因为它运行在浏览器的渲染主线程中,而渲染主线程只有一个。
- 渲染主线程要执行很多任务,解析html,执行js等。
- 如果主线程采用同步的方式执行代码,可能会阻塞主线程的执行,导致消息队列中的其他任务无法执行。会浪费时间,以及导致页面无法及时更新卡死。
- 所以采用异步的方式去解决。当遇到一些异步的任务,渲染主线程将这些任务交给其他线程去处理,自身立即结束执行任务,执行后续代码。当其他线程完成,将事先传递的回调函数包装成任务,放入消息队列的末尾,等待主线程的调度执行。
- 在这种异步模式下,浏览器就不会阻塞,单线程也可以流畅运行。
事件循环
事件循环又称之为消息循环,是浏览器渲染主线程的工作方式。 在chrome的源码中,它开启一个死循环,每次循环从消息队列中取出第一个任务执行,其他线程只需要在合适的时候把任务放入消息队列的末尾即可。 过去就是微任务队列和宏任务队列。目前的浏览器情况更加复杂,灵活的处理。 最新的W3c解释如下:
- 每个任务都有一种任务类型,相同类型的任务必须放在一个队列中,不同类型的任务放在不同的队列中。
- 不同的任务队列有不同的优先级
- 在一次事件循环中,浏览器可根据实际情况选取队列执行任务。
- 但是浏览器必须准备好一个微任务队列,微任务队列中的任务优先其他所有任务执行。必须优先调度。
最开始的时候,渲染主线程会开启无限循环。
- 每一次循环,都会判断消息队列中是否有任务存在,如果有,就执行取出第一个任务执行。执行完以后,进入下一次循环,没有的话,就会进入休眠状态。
- 其他所有线程可以随时向消息队列里面添加任务,新任务会加入消息队列的末尾。如果是休眠状态,会唤醒主线程,继续循环执行任务。 整个过程,就是事件循环(消息循环)
事件循环机制
宏任务主要包括:setTimeout、setInterval
微任务主要包括:promise、process.nextTick()
执⾏规则:同步代码直接进⼊主线程执⾏,JS引擎判断主线程是否为空,如果为空,则读取 微任务Event
Queue 中所有的消息,并依次执⾏。主线程和微任务 Event Queue 都为空后,读取 宏任务Event Queue 中的第⼀个消息进⼊主线程执⾏,来回微宏。
async/await
async/await 是 ES2017(ES8)引入的 基于 Promise 的语法糖,用于更清晰地编写异步代码,使其看起来像同步代码,提高可读性。
async 关键字:用于声明一个异步函数,返回值始终是 Promise。
await 关键字:只能在 async 函数中使用,等待 Promise 解析(resolve)并返回结果,而不会阻塞线程。await命令后面是一个 Promise对象,返回该对象的结果。如果不是 Promise对象,就直接返回对应的值。
不管await后面跟着的是什么,await都会阻塞后面的代码
Promise
- Promise 对象是异步编程的⼀种解决⽅案。Promise 是⼀个构造函数,接收⼀个函数作为参数,返回⼀个 Promise 实例。
- ⼀个 Promise 实例有三种状态,分别是pending、fulfilled 和 rejected。
- 实例的状态只能由 pending 转变 fulfilled 或者 rejected 状态,并且状态⼀经改变,⽆法再被改变了。
- 状态的改变是通过传⼊的 resolve() 和 reject() 函数来实现的,当我们调⽤resolve回调函数时,会执⾏Promise对象的then⽅法传⼊的第⼀个回调函数,当我们调⽤reject回调函数时,会执⾏Promise对象的then⽅法传⼊的第⼆个回调函数,或者catch⽅法传⼊的回调函数。
Promise的实例有两个过程:
pending -> fulfilled : Resolved(已完成)
pending -> rejected:Rejected(已拒绝)
⼀旦从进⾏状态变成为其他状态就永远不能更改状态了。
在通过new创建Promise对象时,我们需要传⼊⼀个回调函数,我们称之为executor
✓ 这个回调函数会被⽴即执⾏,并且给传⼊另外两个回调函数resolve、reject;
✓ 当我们调⽤resolve回调函数时,会执⾏Promise对象的then⽅法传⼊的回调函数;
✓ 当我们调⽤reject回调函数时,会执⾏Promise对象的catch⽅法传⼊的回调函数;
resolve的三种状态
情况⼀:如果resolve传⼊⼀个普通的值或者对象,那么这个值会作为then回调的参数;
情况⼆:如果resolve中传⼊的是另外⼀个Promise,那么这个新Promise会决定原Promise的状态:
情况三:如果resolve中传⼊的是⼀个对象,并且这个对象有实现then⽅法,那么会执⾏该then⽅法,并且根据then⽅法的结 果来决定Promise的状态:
then⽅法接受两个参数:
fulfilled的回调函数:当状态变成fulfilled时会回调的函数;
reject的回调函数:当状态变成reject时会回调的函数;
Promise 串行执行
多个异步操作依次执行(避免回调地狱)
function step1() {
return new Promise((resolve) => setTimeout(() => resolve('Step 1 完成'), 1000))
}
function step2() {
return new Promise((resolve) => setTimeout(() => resolve('Step 2 完成'), 1000))
}
step1()
.then((result) => {
console.log(result)
return step2() // 返回 Promise
})
.then((result) => console.log(result))
.catch((error) => console.error('错误:', error))
输出:
Step 1 完成
Step 2 完成
Promise 并行执行
多个异步任务同时执行,全部完成后再处理
const p1 = new Promise((resolve) => setTimeout(() => resolve('任务 1'), 1000))
const p2 = new Promise((resolve) => setTimeout(() => resolve('任务 2'), 1500))
Promise.all([p1, p2])
.then((results) => console.log('所有任务完成:', results))
.catch((error) => console.error('任务失败:', error))
如果只要最快完成的结果
Promise.race([p1, p2])
.then((result) => console.log('最先完成的:', result))
.catch((error) => console.error('失败:', error))
总结
Promise 解决异步回调问题,提供 .then()、.catch()、.finally() 处理状态变化。支持 Promise.all() 并行执行,Promise.race() 竞争执行。用 async/await 可以让异步代码更清晰。
作用域
- 1.除了函数外,js是没有块级作用域。
- 2.作用域链:内部可以访问外部的变量,但是外部不能访问内部的变量注意:如果内部有,优先查找到内部,如果内部没有就查找外部的。
- 3.注意声明变量是用var还是没有写(window.)
- 4.注意:js有变量提升的机制【变量悬挂声明】
- 声明变量优先级>声明普通函数优先级》参数》变量提升
面试的时候怎么看
1.本层作用域有没有此变量【注意变量提升】 2.除了函数外,js是没有块级作用域。 3.普通声明函数是不看写函数时候的顺序
代码输出题
输出 undefined 2 1
输出 111b
解释:在本层作用域里面找,室友这个name的变量 ,name进行变量提升,undefined
输出 undefined 2
打印 10(声明变量优先级》声明普通函数优先级)
打印 :f a(){}
打印 a(){} //声明普通函数优先级》变量提升
参数》变量提升 打印100
打印10 声明变量优先级>声明普通函数优先级》参数》变量提升
打印 10 这个a是没有var的是全局的a
打印20
打印10 变量的再次赋值
js对象
- 对象都是通过new操作符构建出来的,所以对象之间不相等;
- 注意引用类型的!
- 对象的key都是字符串类型的
- 对象如何找属性
【1,2,3】===【1,2,3】 flase
var obj={a:1}
var obj2=obj
obj===obj2 true
输出:456
因为已经变成字符串了,【Object】
Dom的常见操作
- 查找:通过
getElementById、getElementsByTagName、getElementsByClassName、querySelector及querySelectorAll定位节点。 - 创建:使用
createElement创建元素节点,createTextNode创建文本节点。 - 添加:
appendChild将节点添加到父节点末尾,insertBefore在指定位置插入节点。 - 修改:利用
innerHTML或textContent改内容,直接操作属性改特性,style属性改样式。 - 删除:用
removeChild从父节点移除子节点。 - 替换:使用
replaceChild以新节点替换现有子节点。
面试官:DOM常见的操作有哪些? | web前端面试 - 面试官系列 (vue3js.cn)
事件委托
dom事件流
事件冒泡
事件委托
事件委托是一种在 JavaScript 中用于优化事件处理的技术。它利用了事件冒泡的原理,将多个子元素的事件处理委托给它们的共同父元素,从而减少事件监听器的数量,提高性能。
以下是关于事件委托的详细介绍:
当一个事件在某个元素上触发时,它会按照冒泡阶段从触发事件的元素开始,沿着 DOM 树向上传播到文档根节点。利用这一特性,可以在父元素上添加一个事件监听器来监听子元素触发的事件,然后根据事件对象的target属性来判断具体是哪个子元素触发了事件,进而执行相应的处理逻辑。
可以通过 addEventListener 方法的第三个参数来指定是在捕获阶段还是冒泡阶段处理事件。
addEventListener方法的第三个参数默认值为false,表示在事件冒泡阶段处理事件。
addEventListener方法的第三个参数设置为true,则表示在事件捕获阶段处理事件。
每次触发事件,就会产生event对象。就是点击事件,键盘键入。事件
获取事件目标的对应元素 event.target 获取触发的元素 比如button按钮
比如:一个宿舍取快递,让其中一个去取,不用都取,重点:取回来的发给谁。 需要判断当前响应的事件应该匹配到被代理元素中的哪一个或者哪几个
二、应用场景
如果我们有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候响应一个事件。如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的。这时候就可以事件委托,把点击事件绑定在父级元素ul上面,然后执行事件的时候再去匹配目标元素。
使用 addEventListener 方法来绑定事件处理函数,事件对象会作为参数自动传递给处理函数。
(event.type); // 输出 'click'
event.target:指向触发事件的实际 DOM 元素。
es6的新特性
ES6新增Set、Map两种数据结构
Set是一种叫做集合的数据结构,Map是一种叫做字典的数据结构。
Set是es6新增的数据结构,类似于数组,但是成员的值都是唯一的,没有重复的值,我们一般称为集合。
增删改查
Set的实例关于增删改查的方法:
- add()
- delete()
- has()
- clear()
遍历
Set实例遍历的方法有如下:
关于遍历的方法,有如下:
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回键值对的遍历器
- forEach():使用回调函数遍历每个成员
Set的遍历顺序就是插入顺序
二、Map
Map类型是键值对的有序列表,而键和值都可以是任意类型。
增删改查
Map 结构的实例针对增删改查有以下属性和操作方法:
- size 属性
- set()
- get()
- has()
- delete()
- clear()
遍历
Map结构原生提供三个遍历器生成函数和一个遍历方法:
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回所有成员的遍历器
- forEach():遍历 Map 的所有成员
遍历顺序就是插入顺序
WeakMap
WeakMap结构与Map结构类似,也是用于生成键值对的集合
在API中WeakMap与Map有两个区别:
- 没有遍历操作的
API - 没有
clear清空方法 WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名WeakMap的键名所指向的对象,一旦不再需要,里面的键名对象和所对应的键值对会自动消失,不用手动删除引用- 在网页的 DOM 元素上添加数据,就可以使用
WeakMap结构,当该 DOM 元素被清除,其所对应的WeakMap记录就会自动被移除。
Promise
什么是promise
在平时开发中,会经常碰到异步编程任务,会遇到有一些问题,最突出的是(地狱回调问题),
这种情况通常会出现在需要执行多个异步操作的场景。
有了promsie 可以更好的维护代码,更轻松的处理异步操作。
Promise:是一种用于管理异步操作的对象,基于状态机的概念,可以处于三种状态。
等待中:pending
已完成:fufilled 表示异步操作成功执行
已拒绝:rejected 表示异步操作失败或者出错
构造promise,通过一个new promise 创建一个Promise对象,这个对象包含一个执行器函数 作为参数,接收两个函数resolve 和 reject 作为参数,分别表示promsie 成功完成和失败的情况。
通过promise.then 指定异步任务完成后要执行的代码,也接收两个参数
第一个参数是,异步任务成功执行的回调函数,
第二个参数是,异步任务失败执行的回调函数
异常捕获的方法:
-
promise.then 的 第二个回调函数
-
Catch 方法 用于捕获promise链中任何失败时抛出的异常 :可读性更好,更方便的进行错误传递,错误捕捉更加全面。
Promise引入链式调用:可以更流畅的处理多个异步操作,避免陷入层层嵌套的回调函数中。
fetch 是浏览器提供的一个用于发起网络请求的 API,其返回值是一个 Promise 对象,这个 Promise 对象会在请求完成后被解决(resolved)或被拒绝(rejected)。
onFulfilled:当 Promise 的状态变为 fulfilled 时调用的回调函数,它接收 Promise 的成功结果作为参数。
onRejected:当 Promise 的状态变为 rejected 时调用的回调函数,它接收 Promise 的错误信息作为参数
promise.then(onFulfilled, onRejected);
then 方法本身也会返回一个新的 Promise 对象,这个新的 Promise 对象的状态取决于 onFulfilled 或 onRejected 回调函数的执行结果:
-
如果回调函数返回一个值,新的 Promise 会以该值作为成功结果,状态变为 fulfilled。
-
如果回调函数抛出一个错误,新的 Promise 会以该错误作为失败原因,状态变为 rejected。
-
如果回调函数返回另一个 Promise 对象,新的 Promise 的状态会跟随这个返回的 Promise 对象。
如果任何一个 Promise 被拒绝(rejected),则会跳过后续的 then 方法,直接执行 catch 方法来处理错误。
Promise.all
接收一个promise数组,当数组中所有的Promise对象都完成之后,该方法返回一个成功状态的promise对象,成功的结果是由多个promise对象成功结果组成的数组。
一旦有一个失败,返回失败的promise对象,失败的结果就是其中一个失败的promise的结果。
实际应用:开发一个应用,用户可以创建帖子并上传多个照片,当用户提交帖子的时候,应用程序应该同时上传多个照片,等都上传完成,才能创建帖子。
Promise.race 方法
参数:数组,方法的返回结果是一个promise对象,promise的状态是数组中最先返回结果的状态。结果是最先返回的结果。
实际应用:需要在用户打开应用的时候尽快展示数据,同时从本地缓存和服务器获取数据,只要其中一个完成,不论成功还是失败,都返回相应的结果。尽快让用户看到数据,并且能及时更新数据。