知识点啊啊

V8:https://mp.weixin.qq.com/s?__biz=MzU5NDM5MDg1Mw==&mid=2247487517&idx=2&sn=f5fd6cef41b856ea4f4aca2de915760c&chksm=fe00aa37c97723217acee08b2e20dea2b53ed44b6dc8910aec57b4e9c1c71294847ee681fa1a&token=828996357&lang=zh_CN#rd

git merge/rebase/cherry-pick:https://www.cnblogs.com/ludashi/p/8213550.html
类型判断:
https://www.cnblogs.com/onepixel/p/5126046.html
instance详解及实现
https://blog.csdn.net/weixin_40013817/article/details/103182967

function myInstanceof (left, right) {
    // 基本数据类型直接返回false
    if (typeof left !== 'object' || left === null) return false
    // getProtypeOf是Object对象自带的一个方法,能够拿到参数的原型对象
    let proto = Object.getPrototypeOf(left)
    while (true) {
        // 查找到尽头,还没找到
        if (proto == null) return false
        // 找到相同的原型对象
        if (proto == right.prototype) return true
        proto = Object.getPrototypeOf(proto)
    }
}

原型及原型链:
https://www.cnblogs.com/loveyaxin/p/11151586.html
https://www.cnblogs.com/haishen/p/12055434.html

闭包:
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

执行上下文:
https://juejin.cn/post/6844903682283143181
https://www.cnblogs.com/echolun/p/11438363.html

this的指向可能会为null:
https://blog.csdn.net/qq_45454550/article/details/107879829

回流重绘:
https://juejin.cn/post/6844903569087266823
https://segmentfault.com/a/1190000017329980

将多次操作合并在一起:比如边界修改,修改csstext(会把原来的删掉,可以+=);修改class来修改样式className
需要对dom进行一系列修改时,先脱离文档流再修改,修改完再改回去。display:none
用documentfragment创建一个dom之外的子树,修改完拷贝回来
需要访问与布局相关的属性时最好作为变量保存下来,避免每次都重新计算。
对于复杂的动画效果,设置为绝对定位脱离文档流。
css3硬件加速。
transform
opacity
filters
Will-change
触发硬件加速
可能导致占用内存过大,有性能问题。gpu渲染中字体抗锯齿失效,如果不关闭导致字体模糊

脱离文档流:
https://www.cnblogs.com/ning123/p/11011845.html

浏览器流式布局模型:

伪类:
伪类的顺序应为link–visited–hover–focus–active。

RESTful:
http://www.ruanyifeng.com/blog/2011/09/restful.html
https://www.jianshu.com/p/7893169a7c93

set和array
https://es6.ruanyifeng.com/#docs/set-map
https://blog.csdn.net/weixin_34221036/article/details/88211634

for in 和for of
https://www.webhek.com/post/javascript-loop-foreach-for-in-for-of.html
https://zhuanlan.zhihu.com/p/161892289
https://blog.csdn.net/shangyanaf/article/details/80415236

事件机制和事件委托:
https://blog.csdn.net/qq_38128179/article/details/86293394
https://www.cnblogs.com/liugang-vip/p/5616484.html
https://www.cnblogs.com/snsart/p/10881168.html

图片懒加载
https://zhuanlan.zhihu.com/p/55311726

防抖节流
https://segmentfault.com/a/1190000018428170
https://blog.csdn.net/hupian1989/article/details/80920324

网络攻防

vue双向绑定
vue父子组件通信

vue路由

mutation和action
ea6class

进程和线程:
每个进程都占用一定的内存
各个进程之间相互独立
每个进程可由一个或多个线程组成
各个线程之间相互协作
各个线程共享进程的内存

进程是CPU分配资源的最小单位(能够拥有资源和独立运行的最小单位)
线程是CPU进行调度的最小单位(CPU调度算法)

现在常说的单线程和多线程,也都是指同一个进程内的线程。

Web存储:

https://blog.csdn.net/qq_41694291/article/details/104574835

Web存储就是指Web通信时客户端对少量数据进行本地存储。主要包括cookie、localStorage、sessionStorage和IndexedDB。可以减少HTTP数据传输,提升网站性能。

cookie:

最初的web存储就是cookie。这主要是因为http协议是无状态的,它对两次数据传输是没有记忆的。但是有时候服务端确实需要区分不同的客户端。

于是就有了session机制。session机制就是每当有用户登录后,就为这个用户创建一个会话对象,把用户的信息存储在session对象中,同时产生一个sessionID。将sessionID在set-cookie响应头中传输给客户端,客户端就将这个id存储下来,每次请求都带上这个ID,服务端就能知道是哪个用户发的请求。当用户退出登录或者登录超时时就销毁这个会话对象。

这个唯一的ID就存储在cookie中。cookie中存储的是以name=value的形式存储的字符串,经过了encodeURIComponent编码。除了key和value之外,还存储了域、路径、失效时间、安全标志等,这些参数在使用document.cookie输出时无法看到,不过可以在调试工具中查看:

> document.cookie
< "_ga=77911531582348967; _gid=10966846041582958782"

在这里插入图片描述

其中几个比较重要的参数有:
HttpOnly,是否只能通过http请求传输。某些重要的cookie(如sessionId),只能由后台来设置,并且是不能随意修改的,就可以设置该标志位。
Secure,安全标志。设置了该参数后,该cookie只在https请求中才会被携带。
Expires/Max-Age,cookie的失效时间,以毫秒为单位。不设置时默认在session失效时失效。

//设置coockie
document.cookie = "name=oeschger";//会在服务端session销毁时失效
document.cookie = "favorite=tripe;max-age=120;path=/";//会在120s后失效
alert(document.cookie);
// 显示: name=oeschger; favorite=tripe
document.cookie = "favorite=; max-age=0;";//通过这个方式可以设置cookie过期

cookie的缺点:
1、容量有限,最大4KB,且同一个域下存储的coockie的数量也是有限的,一般不要超过20个
2、安全问题,存储了用户身份信息,如果泄露可能造成损失
3、性能损耗大,在同一域下每次发送请求都会携带,如果cookie很大,会影响响应速度。
所以cookie仅用于保存极少量的用户身份认证信息,而且需要通过加密策略保证cookie传输安全。(密码用MD5加密,将所有信息连接起来后用Base64编码)。

sessionStorage和localStorage:
两者都是HTML5推出的,十分相似。

相同点:
1、都是浏览器端存储
sessionStorage为会话存储,localStorage为本地存储,都部署在windows对象上。

window.localStorage
// 或者直接访问localStorage

window.sessionStorage
// 或者直接访问sessionStorage

2、使用方法相似

localStorage.setItem("name", "carter");  // 设置name: carter

localStorage.age = "24";   // 设置age: 24

localStorage.getItem("name");  // 获取name的值carter

localStorage.removeItem("name"); // 删除name

localStorage.clear();  // 清空localStorage

3、都遵循同源策略
在同一个域下可以共享,跨域无法访问。

4、容量都是5MB左右,只能保存字符串类型的数据。(JSON.stringify来转为字符串,使用的时候再用JSON.parse进行解析)

不同点:

1、失效时间不同
sessionStorage在页面会话有效时有效,页面会话失效时失效,sessionStorage被清空。
localStorage理论上永久都是有效的,可以通过一些策略(setItem中保留创建时间,getItem时判断时间是否失效,如果失效则清除)来定期清除localStorage。

localStorage.setItem("name", JSON.stringify({
  value: "carter",
  time: (new Date()).getTime() // 保存时间戳
}))

function getItem(key, maxAge){
  let obj = localStorage.getItem(key);
  if(obj){  // 获取变量值对象
    obj = JSON.parse(obj);
  }
  // 存储时间小于最大生命周期时才读取该参数,否则将其清除
  if((new Date()).getTime() - obj.time < maxAge){
    return obj.value;
  } else {
    localStorage.removeItem(key);
    return "";
  }
}

getItem("name", 60 * 60 * 1000);  // 失效时间为1小时

2、有效范围不同
sessionStorage只在当前页签有效,localStorage跨页签生效。
比如,打开了一个同域的新页面,sessionStorage中的数据不能共享,localStorage中的数据可以共享。但如果在当前页面的iframe中打开,两者都可以共享。

indexedDB:

前端缓存对性能提升很大,所以前端存储需求也越来越大。
indexedDB时前端的事务型相互句酷,可以存储结构化数据,读写性能好。
所需的流程见参考文章。

跨域

浏览器的同源策略主要是为了保证信息安全,防止信息被窃取。
同源主要指的是协议名、域名、端口号三者都相同。任意一个不同就形成了跨域。
对于非同源的情况,会出现一些限制:
1 cookie localstorage indexdb这些web存储无法获取
2 dom无法获取
3 ajax请求不可进行

1:
对于一级域名相同、二级域名不同的情况下,通过设置document.domain为一级域名可以共享cookie及iframe能够互相访问。

通过js脚本设置

代码

通过服务端的set cookie设置

代码

2 localstorage要通过下面的postmessage

3 两网页不同源时无法拿到对方的dom。
比较突出的例子就是iframe窗口以及用window.open打开的窗口无法与父窗口通讯。

如果一级域名相同二级域名不同可以设置document.domain来规避同源政策,拿到dom。
对于完全不同源的情况,有三种方法:

1 通过url中的hash传递信息
url中#后的hash改变不会引起页面刷新。
父窗口和子窗口通过改变hash以及监听hash变化(onhashchange)来获取信息。

代码

2 通过window.name传递信息

无论是否同源,同一窗口内,前一个网页设置的window.name可以被后一个网页读取到。利用这个特性,父窗口先打开一个不同源的子窗口,子窗口将信息写入window.name,该子窗口再弹出一个与父窗口同源的窗口,此时父窗口就能读取到window.name了。

容量可以很大,但是需要一直监听子窗口的.name。

代码

3 通过postmessage传递信息

HTML5提供的window.postmessage的api可以实现不同窗口通信,不管是否同源。

api代码

4、
ajax请求

浏览器规定ajax请求只能发给同源网址,否则报错。其实发出去了,只是被浏览器拦截了。

解决办法:
1 JSONP
客户端和服务端跨域通信的方式。
利用script元素不受同源政策约束的特性,通过在script中添加url,向服务端请求json数据。url的查询字符串中增加callback回调函数参数,值就是回调函数名。
服务端返回数据时,将数据放在回调函数的参数返回。
由于script返回的脚本直接作为代码执行,回调函数可以直接被调用。

请求到的json数据直接作为对象使用减少了json.parse的解析过程。

只能发送get请求。

2 websocket
是一种通信协议,不受同源政策约束,只要服务端支持,就能实现跨域通信。

3 cors

跨域资源共享
可以发送各种类型的请求。允许浏览器向跨域服务器发送XMLHttpRequest。
需要浏览器和服务器同时支持,主要需要服务器实现cors接口,其余部分浏览器自动完成,用户感受不到。
浏览器可能会添加一些头信息,发送附加的请求等。

cors请求有两类,简单请求和复杂请求。

简单请求:对请求方式、请求头的信息做出限制。

浏览器会在请求中自动添加一个请求头origin,表示请求的源,服务器判断是否在许可范围内。
如果不允许,返回一个正常的http响应,浏览器发现是正常的响应报文后会抛出错误,XMLHttpRequest的onerror会捕捉到。此时状态码可能还是200,是不能进行判断的。

如果允许,返回的http响应中会增加几个响应头信息。

access control allow orgin:设置为请求时origin的值或者为*,表示允许的源。

access control allow credentials:设置是否允许发送cookie。需要与浏览器端的with credentials配合。但如果携带cookie,第一个头信息就不能设置为*,必须指名明确的,与请求网页一致的域名,否则的话不可携带cookie。
此时cookie还是遵循同源策略,仅允许服务器域名创建的cookie上传,其他域名的cookie不会上传,同时也不能用document.cookie访问服务器域名下的cookie

非简单请求:

会发送一次预检请求,询问服务器是否允许相关的源、请求方式、请求头信息。预检请求为options请求。

如果服务器否定了预检请求,浏览器会抛出错误,被XMLHttpRequest的onerror捕捉到
得到肯定答复后会发送正式的XMLHttpRequest请求

跨域:
在这里插入图片描述

定时器

setinterval:考虑到回调函数的执行时间会出现计时不准(长或者短);如果前一个时间没有执行完成,会等待。跟屏幕刷新频率不匹配时会出现画面不流畅
隐藏状态时,间隔小于1s的不执行
setInterval 对自己调用的代码是否报错漠不关心。即使调用的代码报错了,它依 然会持续的调用下去(可以用 setTimeout 解决)

settimeout:如果前一个时间没有执行完成,会等待。跟屏幕刷新频率不匹配时会出现画面不流畅
属于js引擎,存在事件轮询,存在事件队列

requestAnimationFrame:随着显示屏刷新频率,调用回调函数引起的重绘频率等于显示器刷新频率。每次重绘前调用函数,每次都将所有dom操作集中在一起进行
隐藏状态时不会继续执行,再次激活时会从暂停的地方开始。
属于GUI引擎,发生在渲染过程的重排重绘部分,与电脑分辨率一致。

之前提到了 js 引擎,就不得不说浏览器的另外一个引擎—GUI 渲染引擎。在 js 中渲染操 作也是异步的.比如 dom 操作的代码会在事件队列中生成一个任务,js 执行到这个任务时 就会去调用 GUI 引擎渲染。

js 语言设定 js 引擎与 GUI 引擎是互斥的,也就是说 GUI 引擎在渲染时会阻塞 js 引擎计 算.原因很简单,如果在 GUI 渲染的时候,js 改变了 dom,那么就会造成渲染不同步。

Map和Object的区别:
https://www.cnblogs.com/ysx215/p/11387938.html
https://xiaozhuanlan.com/topic/0328751964
https://blog.csdn.net/liangchuannan/article/details/70053038

箭头函数:
https://www.liaoxuefeng.com/wiki/1022910821149312/1031549578462080
https://es6.ruanyifeng.com/#docs/function#%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0
https://www.cnblogs.com/ranyonsue/p/11989281.html

promise:
https://es6.ruanyifeng.com/#docs/promise

js异步编程模型:
js 引擎单线程执行的,它是基于事件驱动的语言。它的执行顺序是遵循一个叫做事件队列 的机制。从图中我们可以看出,浏览器有各种各样的线程,比如事件触发器,网络请求、定时器等等。线程的联系都是基于事件的。js 引擎处理到与其他线程相关的代码,就会分发给其他线程。他们处理完之后,需要 js 引擎计算时就是在事件队列里面添加一个任务.。这个过 程中js 并不会阻塞代码等待其他线程执行完毕。而且其他线程执行完毕后添加事件任务告诉 js 引擎执行相关操作。这就是 js 的异步编程模型.。在指定时间内,将任务放入事件队列,等待 js 引擎空闲后被执行.。

数组的扁平化、去重、排序:
https://www.jb51.net/article/163767.htm
https://www.jb51.net/article/181192.htm

let ary = [1, [2, [3, [4, 5]]], 6];
let str = JSON.stringify(ary);
var arr = [[1, 3, 2, 1],
[5, 3, 4, 8, 5, 6, 5],
[6, 2, 8, 9, [4, 11, 15, 8, 9, 12, [12, 13, [10], 14]]], 
16]
  1. flat
arr_flat = arr.flat(Infinity);
  1. 正则表达式
str = str.replace(/(\[|\])/g, '');
str = '[' + str + ']';
ary = JSON.parse(str);

此时是字符串

ary = str.replace(/(\[|\])/g, '').split(',');
  1. 如果arr数组中有空数组,不使用此方法,用下面的方法;同时得到数组的值是字符串,不是数字
var newArr = arr.toString().split(',')
  1. 递归
var newArr3 = []
function flat(arr) {
  for(var i = 0; i < arr.length; i++) {
    if(arr[i] instanceof Array) {
      flat(arr[i])
    } else {
      newArr3.push(arr[i])
    }
  }
}
flat(arr)
  1. reduce和concat
function flatten(arr) {
  return arr.reduce(
    (a, b) => [].concat(a, Array.isArray(b) && b ? flatten(b) : b),[]);
}
var newArr2 = flatten(ary);
  1. 扩展运算符
    每次展开一层
while (ary.some(Array.isArray)) {
  console.log(ary);
  ary = [].concat(...ary);
}

数组去重:

var newArr1 =[1, 3, 2, 1, 5, 3, 4, 8, 5, 6, 5, 6, 2, 8, 9, 4, 11, 15, 8, 9, 12, 12, 13, 10, 14, 16]
  1. 去重方法一(Set)

Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)。
  ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值

var duplicate = Array.from(new Set(newArr1))
  1. reduce和indexof
    通过数组reduce方法,利用indexOf判断上一次回调返回数组a中是否包含当前元素b的索引,如果不存在,则把b元素加入a数组,否则直接返回a
var duplicate1 = newArr1.reduce((a, b) => {
  if(a.indexOf(b) === -1) {
    a.push(b)
  }
  return a
}, [])
  1. for和indexof
var duplicate3 = []
for(var i = 0; i < newArr1.length; i++) {
  if(duplicate3.indexOf(newArr1[i]) === -1) {
    duplicate3.push(newArr1[i])
  }
}
  1. 利用下标去重
    通过数组的过滤filter方法,利用indexOf获取当前元素ele在被过滤数组farr中的第一个索引值,如果值与当前索引值index相等则返回,如果不相等则过滤。
var duplicate2 = newArr1.filter((ele, index, farr) => {
  return farr.indexOf(ele) === index
})
  1. 排序后去重
function unique3(arr) {
  arr.sort();
  var newArr = [arr[0]];
  for(var i = 1, len = arr.length; i < len; i++) {
    if(arr[i] !== newArr[newArr.length - 1]) {
      newArr.push(arr[i]);
    }
  }
  return newArr;
}
var duplicate4 = unique3(newArr1)

数组排序:

sort

function systemSort(arr) {
  return arr.sort(function(a, b) {
    return a - b
  })
}
var sort = systemSort(duplicate)

冒泡

    // 编写方法,实现冒泡
    var arr = [29,45,51,68,72,97];
    //外层循环,控制趟数,每一次找到一个最大值
    for (var i = 0; i < arr.length - 1; i++) {
        // 内层循环,控制比较的次数,并且判断两个数的大小
        for (var j = 0; j < arr.length - 1 - i; j++) {
            // 白话解释:如果前面的数大,放到后面(当然是从小到大的冒泡排序)
            if (arr[j] > arr[j + 1]) {
                var temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
 
    }
    console.log(arr);//[2, 4, 5, 12, 31, 32, 45, 52, 78, 89]

js中的toString、JSON.stringify、String:
https://www.cnblogs.com/mengfangui/p/9909197.html
https://blog.csdn.net/weixin_40918145/article/details/107508544
https://blog.csdn.net/super92850504/article/details/79496628
https://blog.csdn.net/weixin_38098192/article/details/80926938
https://www.jb51.net/article/163459.htm
https://www.cnblogs.com/ningvsban/p/3660654.html
array。from sort

判断数数组:isArray

手写bind、call、apply

鼠标点击是宏任务还是微任务?

手写promise?

promise实现sleep

promise实现async

new.target

map reduce filter

数据类型

安全

布局

try/catch

canvas

原型中的this??

函数什么时候写在原型里,什么时候写在构造函数里

date math

为什么取到innertext要parseint

正则:
https://blog.csdn.net/h610443955/article/details/81079439

数组api:
https://blog.csdn.net/jjw_zyfx/article/details/95970780
https://blog.csdn.net/weixin_42491987/article/details/112004333
https://blog.csdn.net/qq_29055201/article/details/86530254
https://blog.csdn.net/weixin_42144379/article/details/92648799?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-5&spm=1001.2101.3001.4242

JSON.stringify:
https://www.jb51.net/article/163459.htm
https://www.cnblogs.com/ningvsban/p/3660654.html
https://www.cnblogs.com/yelongsan/p/8662691.html

requestAnimationFrame setTimeout setInterval:
http://caibaojian.com/setinterval.html
https://www.cnblogs.com/flash3d/archive/2014/05/08/3715600.html
https://zhuanlan.zhihu.com/p/168512444
https://www.pianshen.com/article/4865325694/
https://blog.csdn.net/weixin_40851188/article/details/89669416
https://blog.csdn.net/gao531162436/article/details/105628007?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242
https://www.jianshu.com/p/7c42dda386f7

n个promise并发执行:
https://segmentfault.com/a/1190000020175627?utm_source=tag-newest

map和forEach:
https://www.cnblogs.com/amcy/p/10101774.html#_labelTop
https://segmentfault.com/a/1190000013368741?utm_source=channel-hottest
https://www.cnblogs.com/huangqiao/p/12190806.html

同源策略:
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
http://www.ruanyifeng.com/blog/2016/04/cors.html

promise异步加载图片:

function loadImageAsync(url) {
  return new Promise(function(resolve, reject) {
    const image = new Image();

    image.onload = function() {
      resolve(image);
    };

    image.onerror = function() {
      reject(new Error('Could not load image at ' + url));
    };

    image.src = url;
  });
}

promise实现Ajax请求:

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出错了', error);
});

p1是一个 Promise,3 秒之后变为rejected。p2的状态在 1 秒之后改变,resolve方法返回的是p1。由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了 2 秒,p1变为rejected,导致触发catch方法指定的回调函数。

const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => reject(new Error('fail')), 3000)
})

const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => resolve(p1), 1000)
})

p2
  .then(result => console.log(result))
  .catch(error => console.log(error))
// Error: fail

跟传统的try/catch代码块不同的是,如果没有使用catch()方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。

const someAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    // 下面一行会报错,因为x没有声明
    resolve(x + 2);
  });
};

someAsyncThing().then(function() {
  console.log('everything is great');
});

setTimeout(() => { console.log(123) }, 2000);
// Uncaught (in promise) ReferenceError: x is not defined
// 123

上面代码中,someAsyncThing()函数产生的 Promise 对象,内部有语法错误。浏览器运行到这一行,会打印出错误提示ReferenceError: x is not defined,但是不会退出进程、终止脚本执行,2 秒之后还是会输出123。这就是说,Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。

Promise内部的代码会不再执行,但不会影响Promise外部的代码。

Promise.finally的实现:

  1. 无论结果是fullfilled还是rejected都会执行
  2. 返回的是原来的值。
Promise.prototype.finally = function (callback) {
  let P = this.constructor;
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason })
  );
};

为什么需要Promise.resolve(callback()).then(() => value) 而不能直接执行callback, return value?
因为callback如果是个异步操作,返回promise呢?希望等callback执行完再接着执行。

Promise总是会返回原来的值?

// resolve 的值是 undefined
Promise.resolve(2).then(() => {}, () => {})

// resolve 的值是 2
Promise.resolve(2).finally(() => {})

// reject 的值是 undefined
Promise.reject(3).then(() => {}, () => {})

// reject 的值是 3
Promise.reject(3).finally(() => {})

promise.all例子

const databasePromise = connectDatabase();

const booksPromise = databasePromise
  .then(findAllBooks);

const userPromise = databasePromise
  .then(getCurrentUser);

Promise.all([
  booksPromise,
  userPromise
])
.then(([books, user]) => pickTopRecommendations(books, user));

如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result)
.catch(e => e);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]

p1会resolved,p2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。

promise.race应用:
如果指定时间内没有获得结果,就将 Promise 的状态变为reject,否则变为resolve。

const p = Promise.race([
  fetch('/resource-that-may-take-a-while'),
  new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('request timeout')), 5000)
  })
]);

p
.then(console.log)
.catch(console.error);

promise.allSettled应用;

对服务器发出三个请求,等到三个请求都结束,不管请求成功还是失败,加载的滚动图标就会消失。

const promises = [
  fetch('/api-1'),
  fetch('/api-2'),
  fetch('/api-3'),
];

await Promise.allSettled(promises);
removeLoadingIndicator();

注意,一旦结束,状态总是fulfilled,不会变成rejected。状态变成fulfilled后,Promise 的监听函数接收到的参数是一个数组,数组的每个成员都是一个对象,每个成员对应一个传入Promise.allSettled()的 Promise 实例。

const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);

const allSettledPromise = Promise.allSettled([resolved, rejected]);

allSettledPromise.then(function (results) {
  console.log(results);
});
// [
//    { status: 'fulfilled', value: 42 },
//    { status: 'rejected', reason: -1 }
// ]

应用案例:

const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
const results = await Promise.allSettled(promises);

// 过滤出成功的请求
const successfulPromises = results.filter(p => p.status === 'fulfilled');

// 过滤出失败的请求,并输出原因
const errors = results
  .filter(p => p.status === 'rejected')
  .map(p => p.reason);

用promise.all来获取操作是否结束。

const urls = [ /* ... */ ];
const requests = urls.map(x => fetch(x));

try {
  await Promise.all(requests);
  console.log('所有请求都成功。');
} catch {
  console.log('至少一个请求失败,其他请求可能还没结束。');
}

promise.any对比promise.all:
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。

const promises = [
  fetch('/endpoint-a').then(() => 'a'),
  fetch('/endpoint-b').then(() => 'b'),
  fetch('/endpoint-c').then(() => 'c'),
];
try {
  const first = await Promise.any(promises);
  console.log(first);
} catch (error) {
  console.log(error);
}

Promise.any()方法的参数数组包含三个 Promise 操作。其中只要有一个变成fulfilled,Promise.any()返回的 Promise 对象就变成fulfilled。如果所有三个操作都变成rejected,那么await命令就会抛出错误。
或者用:

Promise.any(promises).then(
  (first) => {
    // Any of the promises was fulfilled.
  },
  (error) => {
    // All of the promises were rejected.
  }
);
var resolved = Promise.resolve(42);
var rejected = Promise.reject(-1);
var alsoRejected = Promise.reject(Infinity);

Promise.any([resolved, rejected, alsoRejected]).then(function (result) {
  console.log(result); // 42
});

Promise.any([rejected, alsoRejected]).catch(function (results) {
  console.log(results); // [-1, Infinity]
});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值