ES6–Promise对象
定义:
- JS中进行异步编程的新的解决方案 (旧的是纯回调函数)
- 从语法上说,: Promise 是一个构造函数
- 从功能上说: promise对象用来封装一个异步操作并可以获得其结果
优点:
-
指定回调函数的方式更加灵活
promise: 启动异步任务 => 返回Promise对象 => 给Promise对象绑定回调函数 (甚至可以在异步任务结束后再绑定)
-
支持链式调用, 可以解决回调地狱问题
/*
async , await 回调地狱的终极解决方案
同步的编码方式, 没有回调函数
*/
async function request() {
try{
const result = await doSomething()
const newResult = await doSomethingElse(result)
const finalResult = await doThirdthing(newResult)
} catch(error) {
failureCallback(error)
}
}
Promise对象:代表了未来某个将要发生的操作,通常是异步操作
promise对象可以将异步操作以同步的流程表达出来,避免了层层嵌套的
回调函数(回调地域),ES6的Promise是一个构造函数,用来生成promise实例
execute 执行器函数, 同步执行
常见的API:
const p1 = new Promise((resolve, reject)=> {
resolve('1')
}).then().catch()
const p2 = Promise.resolve('2') // 语法糖
p2.then()
const p3 = Promise.reject('3')
p3.catch()
const pAll = Promise.all([p1, p2, p3])
// pAll 也是一个Promise对象, 只有当后面所有Promise的状态为成功时, 才是成功
pAll.then(
values => {}, // 成功得到的值是resolve()中参数的集合, 顺序一一对应
reason => {} // 失败得到的值是reject() 里的参数
)
const pRace = Promise.race([p1,p2,p3])
// 哪个执行快结果就是哪个
pRace.then(
value => {},
reason => {}
)
基本步骤:
then() 方法返回的结果是 Promise 对象, 对象状态由回调函数的执行结果决定
如果回调函数中返回的结果是 非Promise类型的属性, 状态为成功, 返回值为对象的值
如果返回的结果是Promise类型的属性, 则 该promise内部返回的状态 就决定 then方法 promise 对象的状态
如果抛出异常,新promise 的状态变为 resolved ,reason 为抛出的异常
new Promise((resolve, reject) => {
reject('A')
}).then(
value => {
console.log('onResolved 1 ' + value)
},
reason => {
console.log('onRejected 1 ' + reason)
return undefined
}
).then(
value => {
console.log('onResolved 2 ' + value)
},
reason => {
console.log('onRejected 2 ' + reason)
}
)
// output: onRejected 1 A onResolved 2 undefined
- 链式调用 p.then(value => {} ).then( value => {} )
const p = new Promise( resolve => {
resolve('A')
});
p.then(value => {
return new Promise( resolve => {
resolve(value+'B')
})
}).then(value => {
return new Promise(resolve => {
resolve(value+'C')
})
}).then(value=>{
console.log(value) // ABC
})
- 当一个promise指定多个成功 / 失败回调函数,时, 都会调用
-
pending:初始化,
-
fullfilled:成功,
-
rejected:失败
// 除了 resolve() 和 reject() , 抛出异常也可以使promise 的状态 从pending 变为 rejected const p = new Promise((resolve, reject) => { throw new Error('出错误了') // throw 3 }) p.catch(reason => { console.log(reason) })
- 使用promise实现超时处理,
- 使用promise封装处理ajax请求
- 使用promise实现封装处理ajax请求
let promise = new Promise((resolve,reject)=>{
console.log("111");
//执行异步操作通常是发送ajax请求,开启定时器
setTimeout(()=>{
console.log("333");
//根据异步任务的返回结果来修改promise的状态
//异步任务执行成功
resolve("哈哈");//修改promise的状态为fullfilled;成功状态
// reject();//修改为失败状态
},2000);
console.log("222");
}).catch((e)=>{});
promise.then((data)=>{//成功的回调,也可以写上参数resolve
console.log(data,'成功了');
},()=>{//失败的回调
console.log('失败了');
});
Promise例子—用ajax获取新闻内容
//promise对象案例练习
//获取新闻内容
function getNews(url){
let promise = new Promise((resolve,reject)=>{
//状态:初始化
//执行异步任务
//创建xmlHttp实例对象
let xmlHttp = new XMLHttpRequest();
//绑定监听 readyState
xmlHttp.onreadystatechange = function(){
if(xmlHttp.readyState==4){
if(xmlHttp.status==200){//请求成功
console.log(xmlHttp.responseText);
resolve(xmlHttp.responseText);//修改promise的状态为成功状态
}
}else{//请求失败
reject("暂时没有数据");
}
};
xmlHttp.open('GET',url);
xmlHttp.send();
});
return promise;
}
getNews("address url")
.then((data)=>{
console.log(data);
//发送请求获取内容
let theCommemnt = JSON.parse(data).commemntUrl;//commentUrl是data数据里面的一个地址
let url = "address url"+theCommemnt;
return getNews(url);
},(err)=>{
console.log(err);
})
.then((data)=>{
console.log(data);//上面的then返回的数据
},()=>{
});
-
关键问题
1). 改变Promise 状态和指定回调函数 谁先谁后?
- 都有可能, 正常情况下先指定回调函数再改变状态, 但也可以相反
- 如何先改状态再指定回调?
- 再执行器中直接调用 resolve() / reject()
- 延迟更长时间才调用 then()
- 什么时候才能得到数据
- 如果先指定的回调, 那当状态发生改变时,回调函数就会调用, 得到数据
- 如果先改变的状态,那当指定回调时,回调函数就会调用, 得到数据
2). 异常传透
-
使用promise 的then链式调用时,可以在最后指定失败的回调
-
前面任何操作出了异常,都会传到最后失败的回调中处理
new Promise((resolve, reject) => { reject(1) }).then( value => { return 2 }, reason => { throw reason } // 相当于抛出异常 ).then( value => { return 3 }, ).catch(reason => { console.log(reason) })
3).中断Promise链
-
使用promise 的then链式调用时,在中间中断, 不再调用后面的回调函数
-
办法: 在回调函数中返回一个
pending
状态的 promisenew Promise((resolve, reject) => { reject(1) }).then( value => { return 2 }, reason => { throw reason } // 相当于抛出异常 ).then( value => { return 3 }, ).catch(reason => { console.log(reason) return new Promise(() => {}) // 返回一个pending状态的promise, 中断promise链 }).then()
自定义Promise
八、ES6–Symbol属性
Symbol:ES6中添加了一种原始数据类型symbol(已有的原始数据类型:
String,Number,Boolean,undefined,null,对象)
Symbol属性对应的值是唯一的,解决命名冲突问题,Symbol值不能与其他
数据进行计算,包括同字符串拼串,for in,for of遍历时不会遍历Symbol属性
使用:调用Symbol函数得到symbol值
let symbol = Symbol();
let obj={};
obj[symbol] = “hello”;
2.传参标识
let symbol = Symbol(“one”);
let symbol2 = Symbol(“two”);
console.log(symbol,symbol2);
3.内置Symbol值
除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向
语言内部的使用的方法。
Symbol.iterator:指向该对象默认的遍历方法
let symbol = Symbol("hello");
// alert(typeof symbol);
console.log(symbol);
// console.log(symbol.toString());
let obj = {username:'xiaozhan',age:29};
obj[symbol] = "hello";
console.log(obj);
//for in ,for of 不能遍历Symbol属性
for(let i in obj){
console.log(i);
}
let symbol1 = Symbol('one');
let symbol2 = Symbol('two');
console.log(symbol1==symbol2);//false
//可以用来定义常量
const The_Key = Symbol('the_key');
console.log(The_Key);
2.遍历Set
3.遍历Map
4.遍历字符串
5.遍历伪数组
//数组去重方法
let arr = [1,2,3,4,5,5,6,2];
let arr1 = arr;
arr = [];
let set=new Set(arr1);
for(let i of set){
arr.push(i);
}
console.log(...arr);
let arr3 = [1,2,3,4,5,5,6,2];
let set2 = new Set(arr3);
console.log(...set2);
let btns = document.getElementsByTagName("button");
for(let j of btns){
console.log(j);
}