promise是一种异步编程的解决方法,相比容易陷入回调地狱的回调函数,采用链式调用的方法更合理也更方便。
promise的了解
promise是一种异步编程的解决方法,相比容易陷入回调地狱的回调函数,采用链式调用的方法更合理也更方便。
promise有三种状态:pending(进行中),fullfilled(已成功)和rejected(已失败),接收一个函数作为参数,该函数有两个参数,分别是resolve和reject两个函数,Promise好比容器,里面存放着一些未来才会执行完毕的事件结果,而这些结果一旦生成是无法改变的。
Promise 新建后会立即执行
1.异步加载图片的例子
function loadImageAsync(url) {
return new Promise((resolve, reject) => {
const image = new Image()
image.onload = function () {
resolve(image)
}
image.onerror = function () {
reject(new Error())
}
image.src = url
})
}
let url = "https://cdn.jsdelivr.net/gh/inkwall233/imgcdn/vsbg1.png"
loadImageAsync(url).then((res) => {
console.log(res)
})
2.使用Promise对象实现Ajax操作的例子
const getJSON = function (url) {
const promise = new Promise((resolve, reject) => {
const handler = function () {
if (this.readyState !== 4) {
return
}
if (this.status === 200) {
resolve(this.response)
} else {
reject(new Error(this.statusText))
}
}
const client = new XMLHttpRequest()
client.open("GET", url)
client.onreadystatechange = handler
client.responseType = "json"
client.setRequestHeader("Accept", "application/json")
client.send()
})
return promise
}
getJSON("http://jsonplaceholder.typicode.com/posts")
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
})
Promise的链式调用
Promise.prototype.then()
Promise实例具有then方法,作用是为promise实例添加状态改变时的回调函数
then方法返回的是一个新的Promise实例,
因此可以采用链式写法,即then方法后面再调用另一个then方法。
每次调用返回的都是一个新的promise实例
如果then中返回的是一个结果的话,会把这个结果传递下一次then中的成功回调
如果then中出现异常,会走下一个then的失败回调
如果then中使用了return,那么return的值会被promise.resolve包装
Promise.resolve是个把对象包装成promise对象
Promise.resolve(‘foo’)类似于new Promise(reslove => resolve(‘foo’))
4.Promise.prototype.catch()
此方法是.then(null,rejection)的别名
Promise对象的错误具有冒泡性质,会一直向后传递,直到被捕获为止
getJSON("/post/1.json")
.then(function (post) {
return getJSON(post.commentURL)
})
.then(function (comments) {
// some code
})
.catch(function (error) {
// 处理前面三个Promise产生的错误
})
// 上面代码一共有三个Promise对象:一个由getJSON产生,两个由then()产生,
// 它们之中任何一个抛出的错误,都会被最后一个catch捕获
// 跟传统的try/catch代码块不同的是,如果没有使用catch()方法处理回调函数
// Promise对象抛出的错误不会传递到外层代码,即不会有任何反应。
const someAsyncThing = function () {
return new Promise(function (resolve, reject) {
// 下面一行会报错,因为x没有声明
// resolve(x + 2)
})
}
someAsyncThing().then(function () {
console.log("everything is great")
})
Promise.prototype.finally()
finally()方法用于指定不管Promise对象最后状态如何,都会执行的操作。
p6.finally(() => {
// 语句
})
// 等同于
p6.then(
(result) => {
// 语句
return result
},
(error) => {
// 语句
throw error
}
)
Promise.all()
此方法用于将多个Promise实例,包装成一个新的Promise实例。Promise.all()方法接收一个数组作为参数,p1,p2,p3都是promise实例,如果不是,会调用promise.resolve方法。
- 只有p1,p2,p3的状态都变成fulfilled,p的状态才会变成fullfilled,此时p1,p2,p3的返回值组成一个数组,传递给p的回调函数。
- 只要其中有一个被rejected,p的状态就会变成rejected
Promise.race()
参数是数组,此方法是将对各promise实例,包装成一个新的Promise实例
只要p1,p2,p3其中一个实例率先改变,p的状态就会跟着改变。那个率先改变的Promise实例的返回值,就会传递给p的回调函数
Promise.allSettled()
参数是一组Promise实例作为参数,包装成一个新的Promise实例。
只有等到这些参数实例都返回结果,不管是fulfilled还是rejected,
包装实例才会结束
该方法返回新的Promise实例,一旦结束,状态总是fulfilled
它的监听函数接收的参数是数组,该数组的每个成员都是一个对象*
对应传入Promise.allSettled()的两个Promise实例。
每个对象都有status属性,属性值只能为fulfilled
或rejecte
应用场景
有些时候我们不关系异步操作的结果,只关心这些操作有没有结束
这时,Promise.allSettled()就很有用
Promise.any()
此方法和Promise.all()相对应
手撕Promise
class MyPromise {
constructor(executor) {
// 初始化state为等待态
this.state = "pending"
// 成功的值
this.value = undefined
// 失败的原因
this.reason = undefined
// 成功存放的数组
this.onResolvedCallbacks = []
// 失败存放数组
this.onRejectedCallbacks = []
let resolve = (value) => {
// state改变,resolve调用就会失败
if (this.state === "pending") {
// resolve 调用后,state转化为成功态
this.state = "fulfilled"
// 储存成功的值
this.value = value
// 一旦resolve执行,调用成功数组的函数
this.onResolvedCallbacks.forEach((fn) => fn())
}
}
let reject = (reason) => {
// state 改变,reject调用就会失败
if (this.state === "pending") {
//reject调用后,state转化为失败态
this.state = "rejected"
// 储存失败的原因
this.reason = reason
// 一旦reject执行,调用失败数组的函数
this.onRejectedCallbacks.forEach((fn) => fn())
}
}
// 立即执行exector(),如果exector 执行报错,直接执行reject
console.log(1)
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
// then方法
// then方法中,有两个参数:onFulfilled,onRejected,成功有成功的值,失败有失败的原因
// 当状态state为fulfilled,则执行onFulfilled,传入this.value。
// 当状态state为rejected,则执行onRejected,传入this.value
then(onFulfilled, onRejected) {
// 状态为fulfilled,执行onFulfilled,传入成功的值
if (this.state === "fulfilled") {
onFulfilled(this.value)
}
// 状态为rejected,执行onRejected,传入失败的原因
if (this.state === "rejected") {
onRejected(this.reason)
}
// 当状态state为pending时
if (this.state === "pending") {
console.log('then调用');
// onFulfilled传入到成功数组
this.onResolvedCallbacks.push(() => {
onFulfilled(this.value)
})
// onRejected传入到失败数组
this.onRejectedCallbacks.push(() => {
onRejected(this.reason)
})
}
}
}
let mypromise = new MyPromise((resolve,reject) => {
setTimeout(()=> resolve('sss'),2000)
})
console.log(mypromise)
setTimeout(()=>{console.log('1.5s');},1500)
mypromise.then((res) => {
console.log(res)
})
当resolve在setTimeout内执行,then时state还是pending等待状态,而且then函数也是先执行的
我们就需要在then调用时,将成功和失败存到各自的数组,一旦reject或者resolve,就调用他们
先将then里面的两个函数储存起来,成功或者失败的时候,调用他们。
具体操作是,在then里面判断是pending的情况下,将then的两个参数函数先存储起来
当resolve执行的时候,会拿到值value,再执行then里面的函数。
Promise.all的实现
Promise.resolve = function(cal){
return new Promise((resolve,reject) => {
resolve(val)
})
}
// Promise的race 方法
// race方法接收一个数组为参数,数组的元素如果不是promise对象
// 就会调用Promise.reslove()
const p = Promise.race([p1,p2,p3])
// race方法,当数组中某一个promise对象的状态率先改变
// p的状态跟着改变,
// 那个率先改变的promise实例的返回值,就会传递给p的回调函数
Promise.race = function(promises){
return new Promise((resolve,reject) => {
for(let i = 0 ; i<promises.length ; i++){
promises[i].then(resolve,reject)
}
})
}
// Promise的all方法
// 获取所有的promise,都执行then,把结果放到一个数组中,一并返回
Promise.all = function(promises){
let arr = []
let i = 0
function processData(index,data){
arr[index] = data
i++
if(i === promises.length){
resolve(arr)
}
}
return new Promise((resolve,reject) => {
for(let i=0 ; i<promises.length ; i++){
promises[i].then(data => {
processData(i,data)
},reject)
}
})
}
学习于阮一峰老师的ES6入门