开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情
ES6中的promise
理解以及它的实例方法
// 异步编程的一种解决方案
// 可以解决多个串联的异步操作形成的回调地狱
/**
* 理解:promise是一个构造函数,用来生成promise实例
* new Promise()接受一个函数为参数,这个函数有两个参数:
* resolve -- pending 变成 fulfilled 状态,异步操作成功时候调用;
* reject -- pending 变成 rejected 状态,异步操作失败时候调用
*/
const p = new Promise(function (resolve, reject) {
setTimeout(() => {
const time = new Date().getTime()
if (time % 2 == 0) {
resolve('成功状态:success')
} else {
reject('失败状态:fail')
}
}, 1000);
})
/**
* promise 实例方法:
* then() --- 当实例状态发生改变时候的回调函数,返回一个新的promise实例(也是promise可以链式调用的原因)
* catch() --- 用于指定发生错误的回调函数,通常用来替代then的第二个参数:reason
* finally() --- 不管promise的状态成功还是失败都会执行的操作
*/
p.then((value) => { // 成功状态
console.log(value)
},
// (reason) => { // 失败状态
// console.log(reason)
// }
).catch((value) => { // 通常替代then的失败状态
console.log(value)
}).finally(() => {
console.log('finally:我都会执行这里的代码')
})
问题来了:promise究竟怎么解决回调地狱的呢?
用promise解决回调地狱
// 例如:登录——>拿到歌单数据——>根据歌单获取歌曲列表
// 定时器模拟(回调地狱,代码一直往右递进,可观性差)
// setTimeout(() => {
// console.log(111)
// setTimeout(() => {
// console.log(222)
// setTimeout(() => {
// console.log(333)
// }, 3000);
// }, 2000);
// }, 1000);
// promise解决,then的链式调用(代码往下走,逻辑清晰,可观性好,维护性强)
const p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log(1111)
resolve(2222) // then接收的数据
}, 1000);
})
p.then(value => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(value)
resolve(3333)
}, 2000);
})
}).then(value => {
setTimeout(() => {
console.log(value)
}, 3000);
})
promise.all应用
// 使用:把多个promise实例包装成一个新的promise实例
let p1 = new Promise((resolve, reject) => {
resolve('成功1')
})
let p2 = new Promise((resolve, reject) => {
resolve('成功2')
})
let p3 = new Promise((resolve, reject) => {
resolve('成功3')
})
// 参数可以不是数组,但必须是iterator接口
let pAll = Promise.all([p1, p2, p3])
console.log(pAll)
/**
* pAll由 p1, p2, p3 决定;
* 只有3个都是成功,pAll才会成功;
* 有失败的话,pAll就是失败,并返回第一个失败实例的返回值;
* ☆ 如果作为参数的实例,例如p1, p2, p3,它自己定义了catch方法,一旦rejected,也不会触发pAll的catch方法
*/
pAll.then(value => {
console.log(value) // 全成功:['成功1', '成功2', '成功3'];
}).catch(reason => {
console.log(reason) // 第二个失败:成功2;第二第三都是失败:成功2
})
// 使用场景:多个请求结果合并在一起,等多个结果一起返回再渲染页面,提高用户体验感
function getBanner() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('轮播图数据')
}, 1000);
})
}
function getId() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('用户信息')
}, 2000);
})
}
function getSong() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('歌单列表')
}, 3000);
})
}
function initLoad() {
let all = Promise.all([getBanner(), getId(), getSong()])
all.then(value => {
console.log(value) // 3秒之后返回数据[ '轮播图数据', '用户信息', '歌单列表' ]
}).catch(reason => {
console.log(reason) // 如果有失败,返回第一个失败的结果
})
}
initLoad()
promise.race应用
/**
* 把多个promise包装成一个新的promise;
*
* promise.race --- 第一个改变状态的实例决定race状态,并返回第一个改变状态的实例的返回值;
*/
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('2秒后')
}, 2000);
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('1秒后')
}, 1000);
})
// 参数可以不是数组,但必须是iterator接口
let pAll = Promise.race([p1, p2])
console.log(pAll)
pAll.then(value => {
console.log(value)
})
// 使用场景:请求超时提示
function getRequest() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('请求成功')
}, 4000);
})
}
function timeout() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('网络不好,点击重试')
}, 3000);
})
}
function init() {
Promise.race([getRequest(), timeout()])
.then(value => {
console.log(value)
})
.catch(reason => {
console.log(reason)
})
}
init()
使用promise封装axios
function getAjax(url) {
return new Promise((resolve, reject) => {
// 创建一个实例对象
let xhr = new XMLHttpRequest()
// 新建一个http请求
xhr.open('GET', url, true)
// 发送http请求
xhr.send(null)
// 设置状态的监听函数
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return // 表示请求成功才能继续往下执行
if (xhr.status >= 200 && xhr.status < 300) { // 表示请求成功是否
// 请求成功,把请求结果返回出去
resolve(xhr.response)
} else {
reject(new Error(this.statusText))
}
}
// 设置错误的监听函数
xhr.onerror = function () {
reject(new Error(this.statusText))
}
// 设置响应数据类型
xhr.responseType = 'json'
})
}
getAjax('http://xxxxxx').then(value => {
console.log(value)
}).catch(reason => {
console.log(reason)
})