面试题
如何防止手机页面缩放
<meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"/>
- 作用: 在移动浏览器中,当页面宽度超出设备,浏览器内部虚拟的一个页面容器,将页面容器缩放到设备那么大展示
- 视口的宽度可以通过meta标签设置
此属性为移动端页面视口设置 - width: 视口的宽度,width=device-width: 宽度是设备的宽度
- initial-scale: 初始化缩放,- initial-scale=1.0: 不缩放
- user-scalable: 是否允许用户自行缩放,取值0或1,yes或no
- minimum-scale: 最小缩放
- maximum-scale: 最大缩放
关于meta标签
定义字符编码
<meta charset="utf-8">
针对搜索引擎的关键词
<meta name="keywords" content="HTML, CSS, JavaScript" />
自动刷新
<meta http-equiv="refresh" content="5" />
更多meta标签之间查看w3c官方文档–meta标签
遍历某一元素下的子元素
jQuery版:
function each(element){// element为获取到的jquery对象
var arr = [];
arr.push(element[0]);
// console.log(arr);
if(element.children().length > 0){
element.children().each((index, el) => {
arr = arr.concat(each($(el)));
})
}
return arr;
}
原生版:
function eachJs(element){
var arr = [];
arr.push(element);
if(element.children.length){
for(let el of element.children){
arr = arr.concat(eachJs(el));
}
}
return arr;
}
页面404原因
未找到资源文件
常见http转态码:
- 100: 继续 客户端应当继续发送请求。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。
- 101: 转换协议 在发送完这个响应最后的空行后,将会切换到在Upgrade 消息头中定义的那些协议。只有在切换新的协议更有好处的时候才应该采取类似措施。
- 102: 继续处理 由WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执行。
- 200: 请求成功 处理方式: 获得响应的内容,进行处理
- 201: 请求完成,结果是创建了新资源。新创建资源的URI可在响应的实体中得到 处理方式: 爬虫中不会遇到
- 202: 请求被接受,但处理尚未完成 处理方式: 阻塞等待
- 204: 服务器端已经实现了请求,但是没有返回新的信 息。如果客户是用户,则无须为此更新自身的文档视图。 处理方式: 丢弃
- 300: 该状态码不被HTTP/1.0的应用程序直接使用, 只是作为3XX类型回应的默认解释。存在多个可用的被请求资源。 处理方式: 若程序中能够处理,则进行进一步处理,如果程序中不能处理,则丢弃
- 301: 请求到的资源都会分配一个永久的URL,这样就可以在将来通过该URL来访问此资源 处理方式: 重定向到分配的URL
- 302: 请求到的资源在一个不同的URL处临时保存 处理方式: 重定向到临时的URL
- 304: 请求的资源未更新 处理方式: 丢弃
- 400: 非法请求 处理方式: 丢弃
- 401: 未授权 处理方式: 丢弃
- 403: 禁止 处理方式: 丢弃
- 404: 没有找到 处理方式: 丢弃
- 500: 服务器内部错误 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在的源代码出现错误时出现。
- 501: 服务器无法识别 服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。
- 502: 错误网关 作为网关或者工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
- 503: 服务出错 由于临时的维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。
HTML5 新特性
1, 语义化标签:
标签 | 描述 |
---|---|
<header></header> | 定义了文档的头部 |
<footer></footer> | 定义了文档的尾部 |
<nav></nav> | 定义文档的导航 |
<section></section> | 定义文档中的节 |
<article></article> | 定义页面独立的 |
<aside></aside> | 定义页面的侧边栏内容 |
<detailes></detailes> | 用于描述文档或文档某个部分的细节 |
<summary></summary> | 标签包含 details 元素的标题 |
<dialog></dialog> | 定义对话框,比如提示框 |
2, 增强表单:
输入类型 | 描述 |
---|---|
color | 主要用于选取颜色 |
date | 从一个日期选择器选择一个日期 |
datetime | 选择一个日期(UTC 时间) |
datetime-local | 选择一个日期和时间 (无时区) |
包含 e-mail 地址的输入域 | |
month | 选择一个月份 |
number | 数值的输入域 |
range | 一定范围内数字值的输入域 |
search | 用于搜索域 |
tel | 定义输入电话号码字段 |
time | 选择一个时间 |
url | URL 地址的输入域 |
week | 选择周和年 |
3, 新增表单:
表单元素 | 描述 |
---|---|
<datalist> | 元素规定输入域的选项列表使用 <input> 元素的 list 属性与 <datalist> 元素的 id 绑定 |
<keygen> | 提供一种验证用户的可靠方法标签规定用于表单的密钥对生成器字段。 |
<output> | 用于不同类型的输出比如计算或脚本输出 |
4, 新增的表单属性
属性 | 说明 |
---|---|
placeholder | 属性,简短的提示在用户输入值前会显示在输入域上。即我们常见的输入框默认提示,在用户输入后消失。 |
required | 属性,是一个boolean 属性。要求填写的输入域不能为空 |
pattern | 属性,描述了一个正则表达式用于验证<input> 元素的值。 |
min | 和 max 属性,设置元素最小值与最大值。 |
step | 属性,为输入域规定合法的数字间隔。 |
height | 和 width 属性,用于 image 类型的 <input> 标签的图像高度和宽度。 |
autofocus | 属性,是一个 boolean 属性。规定在页面加载时,域自动地获得焦点。 |
multiple | 属性 ,是一个 boolean 属性。规定<input> 元素中可选择多个值。 |
5, 音频<video />
和视频<audio>
6, canvas标签(画布):
使用JS绘制图形文本
7, svg标签(矢量图):
使用xml格式定义图片
canvas与svg区别
在 SVG 中,每个被绘制的图形均被视为对象。如果 SVG 对象的属性发生变化,那么浏览器能够自动重现图形。
Canvas 是逐像素进行渲染的。在 canvas 中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。
- Canvas
- 依赖分辨率, 与位图一样
- 一个canvas标签是一体的, 没有任何子标签
- 不支持事件处理器
- 弱的文本渲染能力
- 能够以 .png 或 .jpg 格式保存结果图像
- 重绘时性能比较好, 使用于游戏(但是目前大型页游依旧使用flash)
- SVG
- 不依赖分辨率, 与矢量图一样
- svg标签下的内容会以节点形式渲染
- 支持事件处理器
- 最适合带有大型渲染区域的应用程序(比如地图)
- 复杂度高会减慢渲染速度(任何过度使用 DOM 的应用都不快)
- 重绘是消耗新能过大, 不适用于游戏, 可用于小图标(文字图标)
参考: w3school
8, webStorage(存储):
- localStorage: 永久储存, 只有主动删除或卸载浏览器否则永远存在
- sessionStorage: 只储存在当前页面中, 离开页面后失效(删除)
9, 删除的标签
标签 | 说明 |
---|---|
basefont | 规定页面上的默认字体颜色和字号 |
big | 呈现大号字体效果。 |
center | 对其所包括的文本进行水平居中 |
font | 规定文本的字体、字体尺寸、字体颜色 |
s | 标记删除线文本 |
strike | 定义加删除线文本定义 |
tt | 呈现类似打字机或者等宽的文本效果 |
u | 为文本添加下划线 |
frame | 定义 frameset 中的一个特定的窗口 |
frameset | 可定义一个框架集。它被用来组织多个窗口 |
noframes | 那些不支持框架的浏览器显示文本 |
acronym | 标记一个首字母缩写 |
applet | 嵌入一个 Java applet |
isindex | 显示一个对话框,提示用户输入单行文本 |
dir | 定义目录列表 |
10, 重新定义的标签
标签 | 重新定义的作用 |
---|---|
b | 代表内联文本,通常是粗体,没有传递表示重要的意思 |
i | 代表内联文本,通常是斜体,没有传递表示重要的意思 |
dd | 可以同details与figure一同使用,定义包含文本,dialog也可用 |
dt | 可以同details与figure一同使用,汇总细节,dialog也可用 |
hr | 表示主题结束,而不是水平线,虽然显示相同 |
menu | 重新定义用户界面的菜单,配合commond或者menuitem使用 |
small | 表示小字体,例如打印注释或者法律条款 |
strong | 表示重要性而不是强调符号 |
JavaScript
中的this
JavaScript中的this指代函数的当前运行环境
为什么会有this
:
JavaScript中引用类型的赋值是把数据的地址赋给变量, 访问变量时, 会从变量中获取到内存地址, 在用这个地址从内存中获取数据
但是JavaScript中会把函数存储在单独的内存中
所以当函数运行时, 就需要知道, 当前函数运行在哪一个环境(上下文)中, 所以this的出现就是指明函数当前的运行环境(上下文)
Get 和 Post 请求的区别:
Get和Post都是http请求的一种方式
- 1, 传参的不同: Get请求使用URL传递参数, 而Post则使用请求体
- 2, 参数数量: Get的参数数量受URL长度限制
- 3, 参数类型: Get只能使用字符串, Post没有限制
- 4, 安全性: Post比Get更加安全
- 5, 编码格式: Get只能使用URL编码, 而Post支持多种编码格式
- 6, 请求速度: Get请求比Post请求更快,
为什么GET请求比POST请求更快
Get请求会一次性把请求头和请求体一并发送给服务器,
而Post会分两次发送, 第一次发送请求同, 等服务器返回100 continue(代表服务器会处理post请求), 再发送请求体, (但是部分浏览器post请求也是只发送一次)
http的 8 种请求方式
请求方式 | 说明 |
---|---|
GET | 获取资源, 用来请求已被URI识别的资源 |
POST | 传输实体, 向服务器传输数据 |
HEAD | 获得报文首部, 用于确认URI的有效性及资源更新的日期时间等 |
PUT | 传输文件, 用来传输文件,就像FTP协议的文件上传一样,要求在请求报文的主体中包含文件内容,然后保存在请求URI指定的位置 |
DELETE | 删除文件, 服务器删除某个资源 |
OPTIONS | 询问支持的方法, 查询针对请求URI指定资源支持的方法 |
TRACE | 追踪路径, 让Web服务器端将之前的请求通信还给客户端的方法 |
CONNECT | 要求用隧道协议连接代理, 要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信 |
JavaScript 继承:
原型链继承:
把父类的实例作用子类的原型
只能继承到父类的函数, 不能继承到父类的属性
function Father(){}
function Child(){}
Child.prototype = new Father();
借用构造函数
在子类的构造函数使用call()借用父类的构造函数
只能继承到属性, 不能继承到方法
function Father(param){}
function Child(param){
Father.call(this, param);
}
原型式继承法
利用临时空构造函数F,把F的prototype指向父类prototype
再把F的实例作为子类的原型
也只能继承到函数, 无法继承属性, 但是子类少了父类的属性定义
function Father(){}
function Child(){}
function inherit(p){
function F(){}
F.prototype = p;
return new F();
}
Child.prototype = inherit(Father.prototype);
// 或者使用ES5 的Object.create()
Child.prototype = Object.create(Father.prototype);
组合继承
把原型链继承和借用构造函数结合起来, 实现属性和函数的继承
缺点: 会多次执行父类的构造函数
寄生组合继承
把原型链继承和借用构造函数结合起来, 实现属性和函数的继承
完美解决继承问题
ES6 class
使用ES6的
class
和extends
实现继承
class Father {}
class Child extends Father{}
移动端自适应方案
百分百布局(bootstrap栅格系统的实现)
rem布局: 根据屏幕尺寸的大小, 同比的调整rem(根节点)的大小
vue的路由中, history模式和hash模式的区别
url不同
history需要后端支持
scrollBehavior(to, form, savePosition){}
vue 路由的滚动行为, 定义切换路由时滚动到那个位置, 仅仅在支持history.pushState的浏览器中可用
history.pushState参考: 这里
to: 跳转前的路由
from: 跳转后的路由
savePosition: 仅使用浏览器前进后退时可用, 记录上一次该路由的滚动位置
前端页面的优化
Vue的性能优化
- 对路由组件进行懒加载const Foo = () => import(’./Foo.vue’)
- 对第三方文件库引用CDN
- 对代码进行压缩打包处理
前端优化,页面优化JS优化 PC端 移动端使用
- 减少DOM节点操作,使用虚拟DOM vue react等
- 尽量减少ajiax 请求,多次请求同样数据可以多数据进行缓存处理
- 标签中尽量避免出现空的 href src 连接
- 减少cookie等 本地缓存
- 减少for循环的使用次数for循环很影响性能
- 图片的处理,使用精灵图,图片懒加载,预加载等
- 减少重定向
- 图片压缩处理
- 直接引用第三方资源库CDN
jq优化
- jq版本问题,理论来说,版本越高,性能越好
- 选择器性能
id > tag > class > [attr] > :伪类
- 缓存对象
- 链式调用
- 避免频繁的操作DOM节点
- 事件代理
- 尽量用原生的方法
- 封装插件
Vue的声明周期钩子函数
钩子函数 | 说明 |
---|---|
beforeCreate | vue实例创建(newVue())之后, 初始化完成, 创建之前调用, 无数据, 无模板, 未挂载 |
created | vue实例创建完成后调用, 有数据, 无模板, 未挂载 |
beforeMount | vue实例挂载前调用, 有数据, 有模板, 未挂载 |
mounted | vue实例挂载后调用, 有数据, 有模板, 已挂载 |
beforeUpdate | 数据更新前 |
updated | 数据更新后 |
activated | keep-alive 组件激活时调用 |
deactivated | keep-alive 组件停用时调用 |
beforeDestroy | 实例销毁前 |
destroyed | 实例销毁后 |
errorCaptured | 当捕获一个来自子孙组件的错误时被调用 |
react的声明周期钩子函数
钩子函数 | 说明 |
---|---|
getDefaultProps | 设置默认的props,也可以用dufaultProps设置组件的默认属性. |
constructor | 数据的实例化 |
componentWillMount | 组件将要挂载 |
render | 组件挂载 |
componentDidMount | 组件已挂载 |
componentWillReceiveProps | props更新, 接收一个参数: 新的props |
shouldComponentUpdate | 数据(state)更新后, 决定是否更新视图 返回true更新视图 接收两个参数:props和新的state |
componentWillUpdate | 数据已经更新但是视图未更新 接收两个参数:props和新的state 如果上一个生命周期 shouldComponentUpdate 返回 false, 那么这个声明周期不会被执行 |
componentDidUpdate | 视图已经更新 接收两个参数:props和新的state |
componentWillUnmount | 组件卸载 |
cookie, sessionStorage, localStorage的区别
cookie, sessionStorage, localStorage 都是客户端存储的方式
大小 | 数量 | 时效性 | 跟随HTTP请求 | 操作 | |
---|---|---|---|---|---|
cookie | 4k左右 | 50个左右 | 可设置 默认浏览器关闭失效 | 是 | documnet.cookie |
localStorage | 5M | 无限制 | 不可设置 除非主动删除或卸载浏览器, 否则永远存在 | 否 | localStorage.[set|get|remove] |
sessionStorage | 5M | 无限制 | 不可设置 同源同窗口生效 | 否 | sessionStorage.[set|get|remove] |
因为cookie的数据会被http请求携带到服务器, 所以cookie数据应该精简
ajax的过程
创建XMLHttpRequest对象
let xhr = new XMLHttpRequest();
调用open
xhr.open(...);
发送请求send()
xhr.send();
监听转态
xhr.onreadStateChange = () => {}
不同的readState对应的转态:
readState == 0
: 代表对象已经实例化,但是还没调用open()readState == 1
: 代表对象已经调用open(),但是请求还没发送readState == 2
: 代表请求已经发送,但是还没有数据返回readState == 3
: 代表返回部分数据readState == 4
: 代表数据已经全部返回
微信小程序相关文件类型
微信小程序的相关文件类型有:
js, json, wxml, wxss
- 1, js: 脚本文件, 页面的交互逻辑
- 2, json: 配置文件, 页面的配置
- 3, wxml: 结构文件, 页面的内容, 类似于网页中的html文件
- 4, wxss: 样式文件, 页面的样式, 类似于网页中的css文件
几个重要的文件:
app.js, app.json, app.wxss
- 1, app.js: 用于处理程序的生命周期等
- 2, app.json: 用于全局配置小程序的文件路径窗口表现等
- 2, app.wxss: 全局样式文件
css选择器
选择符 | 权重 |
---|---|
ID 选择器 | 100 |
class 选择器 | 10 |
标签 选择器 | 1 |
伪类 选择器 | 10 |
属性 选择器 | 10 |
通配符 | 0 |
行内样式 | 1000 |
!import | 10000 |
继承样式 | 无 |
对于多个选择器构成的选择器, 其权重为多个选择器之和
例如:#id .class tag
权重为 100 + 10 + 1 = 111;
如何处理页面的兼容性
1, ios/安卓混合开发有哪些兼容性问题
- 1, 多图上传问题: 安卓不能上传多张图片,没有什么解决方案
- 2, 浮动问题: 尽量用盒模型布局
- 3, 音频自动播放问题,ios默认不自动播放: 在document上添加点击事件播放音频
- 4, iOS横屏幕会重置字体大小: text-size-adjust: none;
- 5, i iOS手机页面里可滚动内容滚动不流畅:
- 6, 安卓浏览器看背景图片,有的会模糊 : background-size: contain;
- 7, transition闪屏 transfrom-style:preserve-3d
2, 浏览器问题;
Css兼容:
- 低版本常见问题: css
- 1 当图片加 在 IE会出现边框;解决办法: border: 0 none;
- 2 在div中插入图片,图片会在下边撑起三像素: 解决办法: img转换成块级元素;
- 3 双倍浮动问题;给浮动元素添加margin会双倍显示;解决办法: 浮动元素加display: inline
- 4 默认高度,低版本会出现默认高度: 解决办法: font-size: 0;
- 5表单元素行高不一致: 解决: vertical-align: middle;
- 6 百分比BUG 50%+50%>100%,解决 给浮动元素添加标识 clear: right clear;left
- 7 鼠标指针BUG cursor: hand 只能在IE9一下;cursor: point用于ie6以上高级版本
- 8 透明属性opacity: 0-1 ie8: filter: alpha()opacity 0-100)
- Css3 要加前缀
- 1 Chrome: -webkit-
- 2 safari: -webkit-
- 3 opera: -o-
- 4 firefox: -moz-
- 5 ie: -ms-
JS兼容问题
问题 | 方法 |
---|---|
获取样式 (是获取, 不是设置) | getcomputedstyle(el)|| el.currentstyle (IE8) |
window事件源 | e = e || window.event (ie8) |
键盘键码 | e=e.which || e。Keycode |
浏览器默认行为 | event.preventDefault || event.returevale=false |
停止冒泡 | event.stoppropagation || cancecBable=true |
事件监听 | addEventListener || attachEventremoveEventListener || detachEvent |
什么是变量提升, ES6怎么避免?
变量提升, 也叫声明提前
使用var
声明变量, 所有变量的声明都会提前到当前作用域的最开始执行
注意: 只有声明提前了, 赋值没有提前
ES6 中增加了let
和const
关键字用于声明变量
使用let
和const
声明的变量不会出现声明提前, 并且具有块级作用域
keep-alive组件
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
当组件在<keep-alive>
内被切换, 它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。
主要用于保留组件状态或避免重新渲染。
keep-alive的props(属性)
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。
详细参考Vue文档 – keep-alive官方文档
数组去重的方法
利用ES6
集合和数组from
函数
let arr = [1,78,6,5,4,98,5,6,7,98];
let set = new Set(arr);
arr = Array.from(set);
console.log(arr);
使用forEach遍历
let arr = [1,78,6,5,4,98,5,6,7,98];
let newArr = [];
arr = arr.forEach(item => {
if(newArr.indexOf(item) < 0){
newArr.push(item);
}
});
console.log(newArr);
另一种遍历方式(性能更好)
let arr = [1,78,6,5,4,98,5,6,7,98];
let myMap = new Map();
arr = arr.forEach(item => {
myMap.set(item);
});
let newArr = Array.from(myMap.keys());
console.log(newArr);
闭包
闭包就是函数内嵌套函数
在函数中定义的变量, 被内层函数应用后, 不会被垃圾将回收机制回收
优点: 可以使用函数内的变量, 并且不被回收
缺点: 过多使用, 会对内存造成压力
dom节点的操作
节点的获取
document.getElementById('id');
document.getElementByName('name');
node.getElementByClassName('class');
node.getElementByTagName('tag');
node.querySelect('select');
node.querySelectAll('select');
节点的创建
document.createElement('tagName');
document.createTextNode('text');
document.createAttribute('name');
节点的添加
node.appendChild(childNode);
node.innserBefore(childNode);
节点的删除
node.removeChild(childNode);
复制节点
node.cloneNode(true | false);
冒泡排序 和 选择排序
冒泡排序
for(let i=0;i<arr.length;i++){
for(let j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
let temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
选择排序
for(let i=0;i<arr.length;i++){
for(let j=i+1;j<arr.length;j++){
if(arr[i] < arr[j]){
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
JavaScript 同源策略
同源政策,是为了保证用户信息的安全,防止恶意的网站窃取数据的一种限时
什么是同源: 即 协议, 域名, 端口 相同情况下, 才叫同源
三者有一个不同即使不同源, 访问不同源的资源就会造成跨域
跨域的解决方法
- JSONP
利用src不受同源策略的限制, 可以访问不同源的资源
而script
标签期望请求到一段JS代码
所以利用script
标签去请求不同源的后端接口
接口返回一段前端函数调用的JS代码, 并把数据作为参数传入
前端通过函数的处理逻辑获取数据
jsonp理论上不属于ajax请求
- CORS
后端接口设置响应同, 为指定用户或所有用户开发访问权限
- 服务器代理
因为后端访问不受同源策略的影响, 所以可以使用同源的服务器去访问不同源的资源
在把获取到的资源返回给前端
- sorket
sorket没有跨域问题, 可以使用sorket进行前后端数据交换
下面这个ul, 使用JavaScriptd点击li时console.log对应的index
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
- 1, 使用let
for(let i=0;i<ul.children.length;i++){
ul.children[i].onclick = function(){
console.log(i);
}
}
- 2, 使用自定义属性
for(var i=0;i<ul.children.length;i++){
ul.children[i].setAttribute('data-index', i);
ul.children[i].onclick = function(){
// 使用getAttribute获取自定义属性
console.log(this.getAttribute('data-index'));
// 使用dataset获取自定义属性(es5)
// console.log(this.dataset.index);
}
}
- 3, 使用闭包
for(var i=0;i<ul.children.length;i++){
ul.children[i].onclick = (function(i){
return function(){
console.log(i);
}
})(i)
}
- 4, 使用bind
for(var i=0;i<ul.children.length;i++){
ul.children[i].onclick = (function(i){
console.log(i);
}).bind(ul.children[i], i);
}
实现垂直水平居中的方式
- 定位 + margin
position: absolute;/* 父节点要定位 */
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
- 定位 + 负margin
width: 100px;
height: 100px;
position: absolute;/* 父节点要定位 */
top: 50%;
bottom: 50%;
margin-top: -50px;
margin-left: -50px;
- 定位 + transform
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
- 弹性盒(父盒子设置)
display: flex;
justify-content: center;
align-items: center;
vue的组件通信
- 使用Vuex
- 使用自定义事件
- 使用第三方实例
promise 的基本使用和原理
原理是什么查了好久都没查到, 那就自己从头写一个简易的
Promise
吧
// 自定义的Promise类
class MyPromise {
constructor(fn){
let canChange = true;
// 使用ES6代理, 在改变state的值之前做判断, 让state只能修改一次
this.state = new Proxy({value: 'pending'}, {
set(target, key, value, receiver){
if(canChange){
canChange = false;
target[key] = value;
return true;
}else{
return false;
}
}
});
fn(this.resolve.bind(this), this.reject.bind(this));
}
then(success){
if(this.state.value === 'fulfilled'){
success(this.param);
}
return this;
}
catch(fail){
if(this.state.value === 'rejected'){
fail(this.param);
}
return this;
}
resolve(param){
this.state.value = 'fulfilled';
this.param = param;
}
reject(param){
this.state.value = 'rejected';
this.param = param;
}
}
// 成功(resolved)后调用的函数
function success(value){
console.log('success: ', value);
return new MyPromise((resolve, reject) => {
reject('reject2');
})
}
// 失败(reject)后调用的函数
function fail(value){
console.log('fail: ', value);
return new MyPromise((resolve, reject) => {
resolve('resolve2');
})
}
// 使用MyPromise
new MyPromise((resolve, reject) => {
reject(123456);
}).then(success).catch(fail);
Promise的API
1, Promise.prototype.then
为 Promise 实例添加状态改变时的回调函数
then方法的第一个参数是resolved状态的回调函数
第二个参数(可选)是rejected状态的回调函数
2, Promise.prototype.catch
用于指定发生错误时的回调函数
3, Promise.prototype.finally
finally方法用于指定不管 Promise 对象最后状态如何
都会执行的操作。该方法是 ES2018 引入标准的
4, Promise.all
用于将多个 Promise 实例,包装成一个新的 Promise 实例
接收一个Promise实例数组(也可以不是数组, 但是一定要有遍历器)
var p = Promise.all([p1, p2, p3])
只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled
只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected
5, Promise.race
同样是将多个 Promise 实例,包装成一个新的 Promise 实例
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变
那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
6, Promise.resolve
将现有对象转为 Promise 对象
7, Promise.reject
返回一个新的 Promise 实例,该实例的状态为rejected
8, Promise.try
经常遇到一种情况:不知道或者不想区分函数f是同步函数还是异步操作
但是想用Promise来处理它
因为这样就可以不管f是否包含异步操作
都用then方法指定下一步流程
用catch方法处理f抛出的错误
================= 未完待续======================================
-
Node.js 的适用场景和优缺点是什么, 以及对中间件的理解
-
promise 的基本使用和原理
-
webpack loader 是用来处理什么的, 为什么要用到 plugin
-
webpack 打包后的源文件运行原理? (是不是eval啊 >_< )
-
f(1)=1, f(1)(2)=2, f(1)(2)(3)=6, 设置一个函数输出一下的值(这个题看不懂啊)
-
vue-cli 中的 dev.env.js 和 prod.env.js 文件的作用