ES6
1.Promise
Promise是ES6实现异步编程的一种方式
3种状态:pending进行中,fulfilled 已成功,rejected 已失败
2种状态的改变 :pending->fulfilled, pending->rejected
状态一旦改变就不能再变
Promise构造器,会传入一个函数,这个函数的参数是resolve,reject,它们是由js引擎提供的函数。resolve 负责将promise的状态由pending 变为fulfilled, 在异步操作成功时调用,并将异步操作的结果作为参数传递出去。reject将promise的状态由pending 变为rejected, 在异步操作失败时调用,并将异步操作的结果作为参数传递出去。
then 回调,有两个参数,第一个参数指定当Promise的状态变为resolved时的回调函数,是必须的,第二个参数指定当Promise的状态变为rejected时的回调函数,是可选的。
catch 用于指定当异步操作发生错误,变为rejected状态时的回调函数
all 并行异步,Promise.all([promise1,promise2,...]).then(),只有当参数内所有promise都变为resolved时,才会执行then回调,如果有一个为rejected,则回调失败,失败原因是第一个promise失败的原因。
注意:
- 无论是then(),还是catch(), 默认返回值都会被放入promise的resolve里面
- new Promise() 会立即执行,与resolve() 和 reject() 位置无关,then catch回调进入微任务队列
- Promise里如果不调用resolve或reject,就会一直处于Pending状态,then和catch也不会执行
定义:
写法1
new Promise(function(resolve,reject){
resolve(data) 或 return data; 正常执行
reject(error); 或 throw error; 发生错误
}).then( ()=>{
//resolve回调函数
}, ()=>{
//reject回调函数
})
写法2
new Promise(function(resolve,reject){
resolve() 正常执行
reject(); 或 throw “error”; 发生错误
}).then( ()=>{
//resolve回调函数
}).catch(()=>{
//reject回调函数
})
.catch(function(value){
console.log(value);
return new Promise(function(resolve){
resolve(123);
});
})
等价于
.catch(function(value){
console.log(value);
return 123;
})
let p = new Promise(function(resolve,reject){
reject(5)
}).then(()=>{
throw 'error';
},()=>{
console.log('position 1');
return "123"
}).catch((data)=>{
// console.log('position 2',data)
return data;
}).then((value)=>{
console.log('last',value)
});
输出:position 1
last 123
let p = new Promise(function(resolve,reject){
console.log("start");
reject();
}).then(()=>{
console.log("then1");
throw 'error';
},()=>{
console.log('position 1');
return "123"
}).catch((data)=>{
console.log('position 2',data)
return data;
}).then((value)=>{
console.log('last',value)
});
// 输出:start
position 1
last 123
Promise 代码实现
const PENDING=”PENDING”;
const FULFILLED =”FULFILLED”;
const REJECTED=”REJECTED”;
class myPromise{
constructor(){
this.state=PENDING;
this.value=undefined; // 成功传值
this.reason=undefined; // 错误原因
this.successCB=[]; //成功存放的数组
this.failCH=[]; // 失败存放的数组
let resolve=function(value){
if(this.state===PENDING){
this.state=FULFILLED;
this.value=value;
this.successCB.forEach(f=>f());
}
}
}
let reject=function(err){
if(this.state===PENDING){
this.state=REJECTED;
this.reason=err;
this.failCB.forEach(f=>f());
}
}
try{
executor(resolve,reject); //立即执行函数
}catch(e){
reject(e);
}
then(onFulfilled,onRejected){
if(this.state=FULFILLED){
onFulfilled(this.value);
}else if(this.state=REJECTED){
onRejected(this.reason);
}else if(this.state=PENDING){
this.successCB.push(onFulfilled(this.value));
this.failCB.push(onRejected(this.reason));
}
}
}
Promise.all=function(promises){ //输入Promises数组
var count=0;
var list=[];
funtion handle(i,data){
count++;
list.push(data);
if(count==promies.length){
resolve(list);
}
}
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(res=>handle(i,res),error=>reject(error));
}
})
}
2. async VS await
async 将修饰的函数变为一个异步函数,它只是对返回值进行了包装,无论如何都会返回一个promise,本质还是一个函数需要调用才能执行。如果不加await它与Promise是一样的
async function aa(){
return "hello";
}
aa().then((res)=>{
console.log(res); //hello
})
执行顺序问题(常考)
async 遇到await 会阻塞当前代码,先执行await中的同步代码,再跳出async执行主线程内的同步代码,最后再返回async继续向下执行,同步代码执行完后,再执行微任务队列,宏任务队列。
async function async1() {
console.log( '1' )
console.log(await async2())
console.log( '2' )
}
async function async2() {
console.log('3')
setTimeout(
()=>console.log('4')
,0)
console.log( '5' )
}
console.log( '6' )
setTimeout( function () {
console.log( '7' )
}, 0 )
async1();
new Promise( function ( resolve ) {
console.log( '8' )
resolve();
} ).then( function () {
console.log( '9' )
} )
console.log( '10' )
// 6 1 3 5 8 10 2 9(微任务) 7 4 (宏任务)
// 微任务清空,选择第一个宏任务执行,再检查微任务队列。。依次循环
3. 宏任务 VS 微任务
宏任务:script代码,UI渲染,setTimeout/setInterval ajax 鼠标键盘等事件
微任务:process.nextTick promises Object.observe MutationObserver
执行顺序:宏任务和他所产生的微任务是绑定的,一个宏任务执行完成后,这个宏任务所产生的微任务,以及微任务产生的微任务全部执行完后。才会执行下一个宏任务。在执行下一个宏任务之前,就会进行页面渲染。
4. 变量提升
对变量进行提升,只声明,不赋值,值为undefined
var v='Hello World';
(function(){
alert(v); // undefined
var v='I love you';
})()
不只变量,函数的声明式也可以提升,但是函数表达式和箭头函数不能提升。
5. var let const
- var可以变量提升,但let const不可以
- var 只有全局作用域与局部作用域,但let const除了全局局部外,还有块级作用域
- var let 定义的是变量,const 定义的是常量,也就是说其值是不可以改变的,但是对于const类型的对象来说,只是对象的地址不可以改变,对象内容是可以改变的
- var 允许重复声明变量,但let const不允许
- let const 是ES6后才支持的语法
- const具有let所有特性,但是它式不可改变的,(const修饰对象,可以改变对象的值)
6. 事件捕获与事件冒泡
事件捕获:自上而下触发
事件冒泡:自下而上触发 e.stopPropagation() 阻止事件冒泡
addEventListener,第三个参数为true,则是事件捕获,false(默认)为事件冒泡
<div id="parent">
<div id="child" class="child"></div>
</div>
doucument.getElementById(“parent”).addEventListener(“click”,function(){
alert(“parent”);
},true)
doucument.getElementById(“child”).addEventListener(“click”,function(){
alert(“child”);
},true)
7. 事件委托(事件代理)
利用事件冒泡的原理,将本应该注册在子元素上的处理事件注册到父元素上,这样当我们点击子元素时,发现子元素没有对应的事件就会自动到父元素上寻找做出响应。
好处:1.减少DOM操作,优化性能。2. 动态添加的子元素也会有相应的事件。3. 减少事件注册,节省内存空间
parent.addEventListener(“click”,function(event){
var e= event|| window.event;
var target=e.target;
if(target.id===”child1”){ }
})
8. JS设计模式
(1)单例模式,一个类只能有一个对象实例
var single=(function(){
var instance=null;
function Single(name){
this.name=name;
}
return function(name){
if(!instance){
instance=new Single(name);
}
return instance;
}
})();
(2)工厂模式,代替 new 来创建对象,批量制作属性相同的对象实例(指向不同)
function Animal(o) {
var instance = new Object()
instance.name = o.name
instance.age = o.age
instance.getAnimal = function () {
return "name:" + instance.name + " age:" + instance.age
}
return instance
}
var cat = Animal({name:"cat", age:3})
console.log(cat);
(3)构造器模式 使用构造方法创建对象
(4)发布-订阅者模式(观察者模式)
发布者发布多个主题,订阅者订阅主题,发布者通知某个主题的所有订阅者更新数据。
发布者:主题 = 1 : N, 主题:订阅者 = 1:N
优点:降低发布者与订阅者之间的耦合性
class Dep{ //主题
constructor(){
this.subs=[]; //主题的订阅者列表
}
// 添加订阅者
addSubs(sub){
this.subs.push(sub);
}
// 通知所有该主题的订阅者进行更新
notify(){
this.subs.forEach((value,index)=>{
value.update()
});
}
}
class Watcher{ //订阅者 观察者
constructor(val,callback){
this.name=val
this.cb=callback;
}
update(){
console.log(this.name+"更新了");
this.cb(); //更新回调
}
}
var w1=new Watcher("小明",()=>{console.log("更新成功")});
var w2=new Watcher("小红",()=>{console.log("更新成功")});
var w3=new Watcher("小李",()=>{console.log("更新成功")});
var dep=new Dep();
dep.addSubs(w1);
dep.addSubs(w2);
dep.addSubs(w3);
dep.notify();
运行结果:
小明更新了
更新成功
小红更新了
更新成功
小李更新了
更新成功
(5)观察者模式
对象之间是一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会收到通知并自动更新。
9. 对象判等
== 与===判断的是内存地址是否相等
var obj1 = {
name: "Benjamin",
sex : "male"
}
var obj2 = {
name: "Benjamin",
sex : "male"
}
console.log(obj1 == obj2); //false
console.log(obj1 === obj2); //false
var obj3=obj1;
obj1==obj3 //true
obj1===obj3 //true
10. class
// ES6 class 属于一种“语法糖”,对程序的功能并没有什么改进,只是为了方便程序员使用
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function() {
return '(' + this.x + ',' + this.y + ')';
}
等同于
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
// 方法会添加到原型上
toString() {
return '(' + this.x + ',' + this.y + ')';
}
}