柏竹 柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档

柏竹

奋斗柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档
  • 前端必备

  • 技术拓展

  • 前端技巧

    • JavaScript进阶技巧
      • Promise
        • Promise方法
        • Promise.all()
        • Promise.race()
        • Promise手写
        • Promise问题
      • Fetch 请求
        • Get
        • Post
      • Async Await 异步
      • Web存储
        • Cookie
        • localStorage
        • sessionStorage
        • Web存储总结
      • call & apply & bind 构造
        • call
        • call()手写
        • apply
        • bind
    • Vue技巧功能
  • Vue

  • 前端
  • 前端技巧
柏竹
2020-02-18
目录

JavaScript进阶技巧

# Promise

Promise是回调的升级版 , 在处理花费较长时间的任务时 , 使用 Promise 可以进行异步处理 , 防止堵塞

学习来源 : 点击跳转 (opens new window)

响应结构说明 :

  • Prototype : 原型类型
  • PromiseState : pending(等待) / fulfilled(完成) / rejected(拒绝)
  • PromiseResult : 响应数据

案例 1: (检测图片有效)

const imageUrl = '';

const imgPromise = (url) => {
    return new Promise( (resolve, reject) => {
        const img = new Image();
        img.src = url;
        // 加载成功
        img.onload = () => {
            resolve(img);
        }
        img.onerror = () => {
            reject(new Error('图片有误'));
        }
    } );
};

imgPromise(imageUrl)
	.then( img => {
    	console.log('success : ',img)
	})
	.catch(err => {
    	console.log('error: ',err)
	})

案例2 : (随机数判断)

new Promise((resolve, reject) => {
  setTimeout(() => {
      let num = Math.floor(Math.random() * 11);//0-10的随机数
  	  if (num >= 5) {
  	    resolve(num);
  	  } else {
  	    reject(num);
  	  }
  	},1000)
}).then(res => {
  console.log("执行了成功时的回调 , 数值为:"+ res);
}).catch(err => {
  console.log("执行了失败时的回调 , 数值为:"+ err);
})

# Promise方法

# Promise.all()

all()方法 用于处理多个异步任务

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('结果1');
  }, 1000);
})
let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('结果2');
  }, 2000);
})

//Promise.all([])接收多个异步任务 , 放入数组中
Promise.all([p1, p2]).then(results => {//results接收多个参数 , 所以是数组
  console.log(results);//["结果1", "结果2"]
})

# Promise.race()

race()方法 当中的任务谁先完成就执行谁

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('结果1');
  }, 1000);
})
let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('结果2');
  }, 2000);
})
//Promise.race([])中接收多个异步任务 , 放入数组中
Promise.race([p1, p2]).then(result => { //p1和p2 公用同一result , 谁先完成接收谁
  console.log(result);
})

# Promise手写

学习来源 : 点击跳转 (opens new window)

class Commitment {
    // 状态
    static PENDING = '待定';
    static FULFILLED = '成功';
    static REJECTED = '拒绝';
    // 构造方法
    constructor(func) {
        this.status = Commitment.PENDING;
        this.result = null;
        // 保存函数
        this.resolveCallbacks = [];
        this.rejectCallbacks = [];
        // 传入异常对象进行操作
        try {
            func(this.resolve.bind(this), this.reject.bind(this));
        } catch (err) {
            this.reject(err);
        }

    }
    // 失败
    resolve(res) {
        // 事件后执行
        setTimeout(() => {
            if (this.status === Commitment.PENDING) {
                this.status = Commitment.FULFILLED;
                this.result = res;
                this.resolveCallbacks.forEach(call => {
                    call(res)
                });
            }
        });
    }
    // 成功
    reject(res) {
        // 事件后执行
        setTimeout(() => {
            if (this.status === Commitment.PENDING) {
                this.status = Commitment.REJECTED;
                this.result = res;
                this.rejectCallbacks.forEach(call => {
                    call(res)
                });
            }
        });
    }
    then(onFULFILLED, onREJECTED) {
        return new Commitment((resolve, reject) => {
            // 不是函数则传递空函数
            onFULFILLED = typeof onFULFILLED === 'function' ? onFULFILLED : () => { };
            onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { };
            // 如果外部也使用了异步 , 很有可能还是 待定状态
            if (this.status === Commitment.PENDING) {
                this.resolveCallbacks.push(onFULFILLED);
                this.rejectCallbacks.push(onREJECTED);
            }
            if (this.status === Commitment.FULLFILLED) {
                // 异步处理
                setTimeout(() => {
                    onFULFILLED(this.result);
                })
            }
            if (this.status === Commitment.REJECTED) {
                // 异步处理
                setTimeout(() => {
                    onREJECTED(this.result);
                });
            }
        });
    }
}

// 测试实例
console.log('No.1');
let commitment = new Commitment((resolve, reject) => {
    console.log('No.2');
    setTimeout(() => {
        reject('这次一定');
        console.log('No.4');
    });
});
commitment.then(
    res => { console.log(res) },
    err => { console.log(err) }
)
console.log('No.3');

测试步骤说明 : (按照No.x步骤说明)

  1. (待定) new实例
  2. (待定) 异步操作 , 执行 then() , 由于是待定状态进行 数组保存函数(resolve/reject)
  3. (成功) 执行 reject() 里面还有一个异步处理(外部先执行了)
  4. (成功) 执行外部异步 , 最后和 reject() 共同跑完

# Promise问题

# Fetch 请求

Fetch 和 ajax 一样能实现异步请求 , Fetch 请求是基于 Promise对象(响应为Promise)

Fetch 和 ajax 区别 :

  • 当接收到错误HTTP状态码(404/500)时 , 并不会进行 reject()处理(关闭网络才会进行该处理) , 但会在 fetch()处理中返回 Promise对象ok属性为 false 的异常
  • fetch() 可以接收跨域 cookies , 也可 建立跨域会话
  • fetch() 不会发送 cookies . 需要自行修改请求头(下面有)

MDN文档 : 点击跳转 (opens new window)

学习来源 : 点击跳转 (opens new window)

基本语法 :

fetch(url, options).then( res =>{
	//处理http响应
})
.catch( err =>{
	//处理错误
})

Response对象响应结构 : (主要关注 PromiseResult的Response对象 响应数据)

属性 类型 说明
body Object (ReadableStream) 响应体
bodyUsed Boolean
headers Object (Headers) 响应头
ok Boolean 是否成功
redirected Boolean 是否发生跳转
status Number http状态码
statusText String 返回状态文字描述
type String 返回请求类型
url String 来源url

注意 :

  • fetch默认不带cookie 传递cookie时 , 必须在header参数内加上 ==credentials: 'include'== , 才会像 xhr 将当前cookie 带有请求中
  • 请求成功返回 Response对象 / 失败则是 TypeError对象
  • 请求异常捕获操作一般 使用await 搭配 try-catch异常捕获

# Get

fetch(`url`)	
.then(response => response.json())
.then(data => console.log(data));

# Post

fetch('url',{
	method: 'POST',
    body: JSON.stringify({name:'Sans',age:20}),
    headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => console.log(data));

# Async Await 异步

Async 是用于声明异步 function函数 ; Await 是用于等待 异步方法执行完成

Async Await函数 一般会返回Promise对象 (也是基于Promise延伸)

// 返回的是 Promise对象
async function shwo() {
    // 这两条返回是同理的
    // return Promise.resolve('Sans');
    return 'Sans';
}
shwo().then(value =>{
    console.log(value); // Sans
}) 

实例 :

异步最大的痛点就是在多个共同运行时 , 顺序不能同步执行 , 例如以下代码 , 每次执行结果的顺序不一样

const url = "https://gorest.co.in/public/v1/users"
function show(){
    fetch(`${url}/1/`)
		.then(res => res.json())
		.then(json => json.data)
		.then(data => console.log(`${data.name}`))

	fetch(`${url}/2/`)
		.then(res => res.json())
		.then(json => json.data)
		.then(data => console.log(`${data.name}`))
	
	fetch(`${url}/3/`)
		.then(res => res.json())
		.then(json => json.data)
		.then(data => console.log(`${data.name}`))
}
show()

Async Await 解决痛点

const url = "https://gorest.co.in/public/v1/users"
async function show(){
    let res1 = await fetch(`${url}/1/`)
    let json = await res1.json();
    console.log(json.data.name)
    
	let res2 = await fetch(`${url}/2/`)
    let json2 = await res2.json();
    console.log(json2.data.name)
    
	let res3 = await fetch(`${url}/3/`)
    let json3 = await res3.json();
    console.log(json3.data.name)
}
show()

await 会等待请求 , 等待的是当前 async修饰的函数 , 并不会影响主线程

# Web存储

# Cookie

Cookie 是服务器发送到浏览器中的本地小块数据(4Kb大小) , 由于浏览器访问的HTTP是无状态的 , 可以通过Cookie 记录状态信息

MDN文档 : 点击跳转 (opens new window)

Cookie应用方面 :

  • 会话状态管理 (登录状态/记住密码/...)
  • 个性化设置 (自定义设置/主题/...)
  • 浏览器行为跟踪

Cookie 是早期开发的 , 存储小 , 每次请求都携带(额外开销) , Cookie 也逐渐被淘汰

存储形式 : 名值对字符串形式存储

操作示例 :

// 存储
let key = "Sans";
let value = encodeURIComponent("");
document.cookie = `${key}=${value}`;

// 提取
// 分割结果 [['user',"xxx"],['Jone','xxx']]
let array = document.cookie
	.split(';') // 分割结果 ['Sans=xxx','Jone=xxx']
	.map( cookie => cookie.split('=') ); 

value 进行 URL编码 是为了防止输入 非法字符(空格/分号/...) 问题

有效期设置 :

只需在后面添加参数 max-age=时间量 (单位s)

// 两天
let twoDays = 2 * 24 * 60 * 60;
document.cookie = `${key}=${value}; max-age=${twoDays}`;

# localStorage

永远存储至浏览器(可手动删) , 有同步机制(影响渲染)

MDN文档 : 点击跳转 (opens new window)

存储形式 : 键值对字符串形式存储

操作示例 :

// 存储
localStorage.setItem('myCat', 'Tom');
// 提取
let cat = localStorage.getItem('myCat');
// 移出
localStorage.removeItem('myCat');
// 清空
localStorage.clear();

# sessionStorage

存储于 当前浏览器会话 , 一旦关闭则失效(安全性高)

MDN文档 : 点击跳转 (opens new window)

存储形式 : 键值对字符串形式存储

操作示例 : 和localStorage操作方式一致

注意 :

  • 页面一旦刷新 sessionStorage 就失效
  • 浏览器另开一个新窗口(每个页面都有各自的sessionStorage) , sessionStorage 也不会共享

# Web存储总结

cookie localStorage sessionStorage
大小 4Kb 10Mb 5Mb
兼容 H4/H5 H5 H5
访问 任何窗口 任何窗口 同一窗口
有效期 手动设置 无 窗口关闭
存储位置 浏览器&服务器 浏览器 浏览器
与请求一同发送 Y N N
语法 复杂 简易 简易

# call & apply & bind 构造

JavaScript函数都是 Funcation对象 是构造函数 , 构造函数有 Funcation.prototype原型对象 , 原型对象 里面包含有很多属性(call)

# call

call()方法 指定的 this 值和单独给出的 一个/多个 参数来调用一个函数

意图 : call() 实现在不同对象 分配/调用 一个对象的 函数/方法

MDN文档 : 点击跳转 (opens new window)

**语法 : ** ==function.call(thisArg, arg1, arg2, ...)==

参数 选择 说明
thisArg 可选 在 function函数 运行时使用的 this 值
arg... 可选 传递的数据

实例可以看以上链接文档

# call()手写

function person( a , b , c , d){
    return {
        name: this.name,
        a: a, b: b, c: c, d:d
    }

}

var people = { name:'Sans' };

Function.prototype.newCall = function (obj) {
    // 对象obj不存在指向window
    var obj = obj || window;
    // this指定的并非为 person , 因此需要绑定
    obj.p = this;
    let newArray = [];
    for(let i = 1 ; i < arguments.length ; i++){
        // 最终结构 [ 'arguments[1]', 'arguments[2]', 'arguments[3]', 'arguments[4]' ]
        newArray.push('arguments[' + i + ']')
    }
    // 执行方法
    var res = eval('obj.p('+newArray+')');
    delete obj.p;
    return res;
};

// 测试代码
let p = person.newCall( people , 'No.1' , 'No.2' , 'No.3' , 'No.4');
console.log(p);

# apply

apply() 方法语法作用和 call()相同 , 唯独区别在 接收的是参数列表

MDN文档 : 点击跳转 (opens new window)

语法 : ==apply(thisArg, argsArray)==

参数 选择 说明
thisArg 可选 在 function函数 运行时使用的 this 值
argsArray 可选 数组/类数组对象

# bind

#技巧
上次更新: 2023/03/12, 00:43:49

← Sass Vue技巧功能→

最近更新
01
HTTPS自动续签
10-21
02
博客搭建-简化版(脚本)
10-20
03
ruoyi-vue-plus-部署篇
07-13
更多文章>
Theme by Vdoing | Copyright © 2019-2024 | 桂ICP备2022009417号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式