一、Promise是什么?
理解
什么是 Promise ?
- Promise 就是一个对象,用来表示并传递异步操作的最终结果
- Promise 最主要的交互方式:将回调函数传入 then 方法来获得最终结果或出错原因
- Promise 代码书写上的表现:以“链式调用”代替回调函数层层嵌套(回调地狱)
1. 抽象表达
-
Promise
是一门新的技术(ES6规范) -
Promise
是JS中进行异步编程的新解决方案
-
Promise就是为解决“回调地狱”而生的
备注:旧的方案是单纯使用回调函数
2. 具体表达
- 从语法上来说:
Promise
是一个构造函数 - 从功能上来说:
Promise
对象用来封装一个异步操作并可以获取其成功或失败的结果值。
- Promise 对象用来进行延迟(deferred) 和异步(asynchronous ) 计算
二、Promise对象的状态改变
Promise
的状态指的是实例对象中的一个属性PromiseState
,它的值有三个:
pending
:未决定的resolve/fulfilled
:成功rejected
:失败
Promise
的状态改变只有下面的三种情况:
- 由
pending
变为resolved
- 由
pending
变为rejected
- 抛出异常:如果当前为
pending
就会变为rejected
说明:只有这3种,且一个Promise
对象只能改变一次,无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般称为value
,失败的结果数据一般称为reason
。
简单使用:
var $ = {
//基于回掉函数机制
get({url,success,error}){
// 异步交互
// 1.new xhr实例
let xhr = new XMLHttpRequest();
// 2.设置请求行
xhr.open('get', url,);
// 3.设置请求头
xhr.setRequestHeader('content-type', 'application/json');
// 设置请求返回格式
// xhr.responseType = 'json';
// 4.发送请求
xhr.send();
// 监听
xhr.onreadystatechange = function() {
if(this.readyState == 4 && this.status==200){
success(this.response)//回调函数
}else{
error(this)
}
}
}
}
$.get({
url:'http://47.100.226.238:8888/index/category/findAll',
success:function(res){
console.log(res);
console.log(JSON.parse(res));//转为json对象
},
error:function(res){
console.log(res)
}
})
var axios = {
//基于承诺对象Promise机制
get(url){
return new Promise(function(resolve,reject){
//1.new xhr实例
let xhr = new XMLHttpRequest();
//2.设置请求行
xhr.open('get',url)
//3.设置请求头
xhr.setRequestHeader("Content-Type", "application/json")
// 设置请求返回格式 最简单方式
xhr.responseType = 'json';
//4.发送请求
xhr.send()
//5.监听
xhr.onreadystatechange = function(){
if(this.readyState == 4){
if(this.status == 200){
resolve(this.response)
}else {
reject(this.response)
}
}
}
})
}
}
//使用
let t=axios.get('http://47.100.226.238:8888/index/carousel/findAll');// t是承诺对象(要使用.then,里面还可能用回调函数)
t.then((res)=>{
// then方法是定义在原型对象Promise.prototype上的。
// 它的作用是为 Promise 实例添加状态改变时的回调函数。
// then方法的第一个参数是resolve,第二个是rejected
console.log(res);
})
.catch((err)=>{
console.log(err);
})
三、为什么要使用Promise?
1. 指定回调函数的方式更加灵活
- 旧的:必须在启动异步任务前指定
- promise:启动异步任务=> 返回promise对象=>给promise对象绑定回调函数(甚至可以在异步任务结束后指定一个或多个)
2. 支持链式调用(就是可以加多个.then()),可以解决回调地狱问题
- then方法是定义在原型对象Promise.prototype上的。
- 它的作用是为 Promise 实例添加状态改变时的回调函数。
- then方法的第一个参数是resolve,第二个是rejected
什么是回调地狱?
回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件
回调地狱的缺点? 不便于阅读 / 不便于异常处理
解决方案? promise链式调用
终极解决方案? async/await
JS 异步编程进化史:callback -> promise -> generator -> async + await
回调地狱
$.ajax({
url:"查询用户",
success:function(res){
console.log(res)
// 将数据渲染到页面上
$.ajax({
url: "查询到课程",
success:function(res){
// 获取到了课程内容的数据,渲染到页面上
$.ajax({})
}
})
}
})
promise 处理回调地狱
new Promise(function(resolve, reject){
$.ajax({
url:"查询用户",
success:function(res){
resolve(res)
},
error:function(err){
reject(err)
}
})
}).then(res=>{
console.log(res)
return new Promise(function(resolve,rejeect){
$.ajax({
url: "查询到课程",
success:function(res1){
// 获取到了文章详细内容的数据,渲染到页面上
resolve(res1)
},
error:function(err){
reject(err)
}
})
})
}).then(res=>{
console.log(res)
return new Promise(function(resolve,rejeect){
$.ajax({
url: "查询到分数",
success:function(res1){
// 获取到了文章详细内容的数据,渲染到页面上
resolve(res1)
},
error:function(err){
reject(err)
}
})
})
}).then(res=>{
console.log(res)
})
封装一下 Promise
function get(url) {
return new Promise((resolve, reject) => {
$.ajax({
url: url,
success: function (data) {
resolve(data);
},
error: function (err) {
reject(err)
}
})
});
}
//调用封装后的方法
get("查询用户")
.then((data) => {
console.log("用户查询成功~~~:", data)
return get("查询到课程);
})
.then((data) => {
console.log("课程查询成功~~~:", data)
return get("查询到分数);
})
.then((data) => {
console.log("课程成绩查询成功~~~:", data)
}).catch((err) => {
console.log("出现异常", err)
});
async function foo() {
try {
const result = await doSomething();
const newResult = await doSomethingElse(result);
const finalResult = await doThirdThing(newResult);
console.log(`Got the final result: ${finalResult}`);
} catch(error) {
failureCallback(error);
}
}
Promise.all
可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
et p1 = new Promise((resolve, reject) => {
resolve('成功了')
})
let p2 = new Promise((resolve, reject) => {
resolve('success')
})
let p3 = Promse.reject('失败')
Promise.all([p1, p2]).then((result) => {
console.log(result) //['成功了', 'success']
}).catch((error) => {
console.log(error)
})
Promise.all()执行顺序和返回顺序 (返回的是对象)
// 方法promiseA,返回一个Promise对象
function promiseA() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('A')
resolve('A')
}, 3000)
})
}
// 方法promiseB,返回一个Promise对象
function promiseB() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('B')
resolve('B')
}, 1000)
})
}
// 按照A, B的顺序添加到promise数组中
Promise.all([promiseA(), promiseB()]).then(resolve => {
console.log(resolve)
})
// 输出情况
B
A
Array [ "A", "B" ]
console.log()可以看出的确是按照谁执行的快谁先打印结果, 但是最终返回的结果仍然是按照promise的添加顺序返回的