promise
promise的基础
promise 接受一个执行器,该执行有两个参数一个参数是成功时执行的函数resolve,一个是失败是执行的函数reject
promise 有三种状态分别是pendding(等待)、fulfilled(成功)、rejected(失败)。
状态 pendding ----> fulfilled 或者 pendding ----> rejected 只会发生一种状态改变并且状态一旦改变就不会再变
resolve函数和reject函数会改变状态
// 首先设置三种状态常量
const PENDDING = 'pendding';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected'
class Mypromise {
constructor(executor) {
// new promise是会立即执行执行器,并且接受两个参数, resolve函数和reject函数
executor(resolve, reject)
}
// resolve是一个函数
resolve = () => {
}
// reject也是一个函数
reject= () => {}
}
我们需要有一个status用来获取当前执行时的状态,
resolve函数执行时候将当前状态改为fulfilled
reject函数执行时候将当前状态改为rejected
constructor(executor) {
// new promise是会立即执行执行器,并且接受两个参数, resolve函数和reject函数
// resolve和reject是实例属性
executor(this.resolve, this.reject)
}
// 当前状态 实例化是pendding
status = PENDDING;
// resolve是一个函数, 参数是响应值
resolve = (response) => {
this.status = FULFILLED; // 修改状态FULFILLED
}
// reject也是一个函数, 参数是错误消息
reject= (errmessage) => {
this.status = REJECTED; // 修改状态REJECTED
}
// 每个实例都可以调用then函数, 该函数接受两个回调函数,
then = (successFn, failureFn) => {
// 当前状态成功了执行successFn
// 当前状态失败了执 failureFn
if(this.status === FULFILLED) {
successFn()
} else if(this.status === REJECTED) {
failureFn()
}
}
then 第一个回调函数接收到resolve中的响应数据, 第二个回调函数接收reject中的失败信息
因此我们要在实例化的时候存储响应数据和失败信息
response = undefined; // 定义一个成功的响应值
errmessage = undefined // 失败的信息
// resolve是一个函数, 参数是响应值
resolve = (response) => {
this.status = FULFILLED;
this.response = response; // 缓存成功消息
}
// reject也是一个函数, 参数是错误消息
reject= (errmessage) => {
this.status = REJECTED;
this.errmessage = errmessage // 缓存失败信息
}
then = (successFn, failureFn) => {
// 当前状态成功了执行successFn
// 当前状态失败了执行 failureFn
if(this.status === FULFILLED) {
successFn(this.response) // 执行成功的回调 参数是成功的响应数据
} else if(this.status === REJECTED) {
failureFn(this.errmessage ) // 执行失败的回调 参数是失败信息
}
}
const p = new Mypromise((resolve, reject) => {
resolve('成功')
reject('失败')
})
p.then(res=> {
console.log(res)
}, err=> {
console.log(err) // 失败 很明显这里打印了失败,说明状态 PENDDING ---- FULFILLED ----REJECTED;
})
// 失败 很明显这里打印了失败,说明状态 PENDDING ---- FULFILLED ----REJECTED;
// 分析一下 状态只能 由pendding --- fulfilled 或者 pendding --- rejected
resolve = (response) => {
// 这里刚开始执行状态如果不是pendding return出去
if(this.status !== PENDDING ) return
this.status = FULFILLED;
this.response = response; // 缓存成功消息
}
// reject也是一个函数, 参数是错误消息
reject= (errmessage) => {
// 同理
if(this.status !== PENDDING ) return
this.status = REJECTED;
this.errmessage = errmessage // 缓存失败信息
}
const p = new Mypromise((resolve, reject) => {
resolve('成功')
reject('失败')
})
p.then(res=> {
console.log(res) // 成功
}, err=> {
console.log(err) // 程序不走这里说明状态只会改变依次
})
处理异步
promise是处理异步操作。。。 如果程序仅仅是这样,那么加入了异步操作会怎样?
////////
const p = new Mypromise((resolve, reject) => {
setTimeout(() => {
resolve('hello')
}, 2000)
})
p.then(res=> {
console.log(res) // 不走
}, err=> {
console.log(err) // 不走
})
// 分析then:
// 1. 走到then函数中, this.status 此时是 pendding。 因为2s之后才会执行resolve,才会改变状态
then = (successFn, failureFn) => {
// 当前状态成功了执行successFn
// 当前状态失败了执行 failureFn
if(this.status === FULFILLED) {
successFn(this.response) // 执行成功的回调 参数是成功的响应数据
} else if(this.status === REJECTED) {
failureFn(this.errmessage ) // 执行失败的回调 参数是失败信息
}
}
-
因此then中需要考虑 如果是pendding 状态 ;
-
2s之后如果是fulfilled状态了 我们应该再走successFn; 如果是rejected状态走 failureFn
-
那么我们如何在2s之后的resolve中拿到 successFn ; 如果在2s之后的reject中拿到 failureFn
// 首先我们定义属性succcessCallback
succcessCallback = undefined;
failureCallback = undefined;
then = (successFn, failureFn) => {
// 当前状态成功了执行successFn
// 当前状态失败了执行 failureFn
if(this.status === FULFILLED) {
successFn(this.response) // 执行成功的回调 参数是成功的响应数据
} else if(this.status === REJECTED) {
failureFn(this.errmessage ) // 执行失败的回调 参数是失败信息
} else {
// 如果在1ms执行到这里还是 pendding状态我们 储存successFn和 failureFn
this.succcessCallback = successFn;
this.failureCallback = failureFn;
}
}
// 然后在resolve函数中
resolve = (response) => {
// 这里刚开始执行状态如果不是pendding return出去
if(this.status !== PENDDING ) return
this.status = FULFILLED;
this.response = response; // 缓存成功消息
// 当异步操作2s后执行到resolve的时候 如果succcessCallback 存在那么执行succcessCallback
this.succcessCallback && this.succcessCallback(this.response)
}
// 在reject函数中
reject= (errmessage) => {
// 同理
if(this.status !== PENDDING ) return
this.status = REJECTED;
this.errmessage = errmessage // 缓存失败信息
// 当异步操作2s后执行到reject的时候 如果failureCallback 存在那么执行failureCallback
this.failureCallback && this.failureCallback (this.errmessage )
}
const p = new Mypromise((resolve, reject) => {
setTimeout(() => {
resolve('hello')
}, 2000)
})
p.then(res=> {
console.log(res) // 2s后打印hello
}, err=> {
console.log(err) // 不走
})
异步连续调用
const p = new Mypromise((resolve, reject) => {
setTimeout(() => {
resolve('111')
}, 2000)
})
p.then(res=> {
console.log(res)
}, err=> {
console.log(err)
})
p.then(res=> {
console.log(res + 'hi')
})
p.then(res=> {
console.log(res + 'say')
})
如上 then的连续调用我们如何解决呢
我们在then的异步操作中,我们可以将回调函数存储起来,在2s之后执行resolve函数时依次拿到存储的回调函数然后执行
succcessCallback = []; // 用数组进行储存所有成功回调
failureCallback = []; // 用数组进行储存所有失败回调
resolve = (response) => {
if(this.status !== PENDDING ) return
this.status = FULFILLED;
this.response = response; // 缓存成功消息
// 当异步操作2s后执行到resolve的时候 如果succcessCallback 存在那么执行succcessCallback
//this.succcessCallback && this.succcessCallback(this.response)
// 判断长度如果不为空, 用shift拿到数组的首个cb去执行
while (this.succcessCallback.length) this.succcessCallback.shift()(this.response)
}
// reject也是一个函数, 参数是错误消息
reject= (errmessage) => {
if(this.status !== PENDDING ) return
this.status = REJECTED;
this.errmessage = errmessage // 缓存失败信息
// 当异步操作2s后执行到reject的时候 如果failureCallback 存在那么执行failureCallback
//this.failureCallback && this.failureCallback (this.errmessage )
// 判断长度如果不为空, 用shift拿到数组的首个cb去执行
while (this.succcessCallback.length) this.failureCallback.shift()(this.errmessage)
}
then = (successFn, failureFn) => {
// 当前状态成功了执行successFn
// 当前状态失败了执行 failureFn
if(this.status === FULFILLED) {
successFn(this.response) // 执行成功的回调 参数是成功的响应数据
} else if(this.status === REJECTED) {
failureFn(this.errmessage ) // 执行失败的回调 参数是失败信息
} else {
// 如果是pendding状态我们首先储存所有succcessCallback 和 failureCallback
this.succcessCallbac.push(successFn);
this.failureCallback.push(failureFn);
}
}
// 2s后打印如下
hello
hellohi
hellosay
then后面还可以链式调用then方法
-
then的链式调用说明then return了一个promise
-
return的promise根据promise的执行结果去链式调用下一个then
-
如果promise的结果时reolve 并且时一个普通值 ?
-
如果promise的结果时reolve 并且是一个promise对象?
then = (successFn, failureFn) => {
// 实例化pr
const pr = new Mypromise((resolve, reject) => {
// 当前状态成功了执行successFn
// 当前状态失败了执行 failureFn
if(this.status === FULFILLED) {
let res = successFn(this.response) // 执行成功的回调 参数是成功的响应数据
resolvePromise(res, resolve, reject) // 处理成功时结果
} else if(this.status === REJECTED) {
failureFn(this.errmessage ) // 执行失败的回调 参数是失败信息
} else {
// 如果是pendding状态我们首先储存succcessCallback 和 failureCallback
this.succcessCallback.push(successFn);
this.failureCallback.push(failureFn);
}
})
return pr; // 返回一个promise
}
------------------------------------
// 如果successFn执行 res=> {} 如果返回一个普通值 ,那么下一个链式then的 res 就是这个值
.then(res => {
})
// 如果successFn执行 res=> {} 如果返回promise对象,那么下一个链式then的 res 就是promise的结果
.then(res => {
})
----------------------------
// res是successFn执行的结果, resolve是成功的回调, reject是结束的回调
function resolvePromise(res, resolve, reject) {
if (res instanceof Mypromise) {
// 执行结果是一个promise
// 调用then方法拿到执行结果如果成功执行resolve
// 失败就调用reject
// res.then(value => resolve(value), err => reject(err))
res.then(resolve(value),reject(err))
} else {
// 普通值直接调用resolve方法
resolve(res)
}
}
const p = new Mypromise((resolve, reject) => {
// setTimeout(() => {
// resolve('hello')
// }, 2000)
resolve('hello')
})
p.then(res=> {
console.log(res) // 打印hello
return 1000
}, err=> {
console.log(err)
}).then(res => {
console.log(res) // 打印1000
})
promise链式调用捕获错误
- 如果实例化Mypromise发生了错误, 应当在then执行时去执行错误回调failureFn
constructor(executor) {
// new promise是会立即执行执行器,并且接受两个参数, resolve函数和reject函数
// 执行器执行时发生了错误用try cathch去捕获执行器执行
try {
executor(this.resolve, this.reject)
} catch (e) {
// 如果有错误直接执行reject
this.reject(e)
}
}
const p = new Mypromise((resolve, reject) => {
throw new Error('executor错误') // 抛出一个错误
})
p.then(res=> {
console.log(res)
return 1000
}, err=> {
console.log(err '---') // Error: executor错误--- failureFn回调执行
}).then(res => {
console.log(res)
})
- 如果then中发生了错误需要在链式的下一个then中去执行failureFn
// then中发生的错误 也用try catch捕获
try {
let res = successFn(this.response) // 执行成功的回调 参数是成功的响应数据
resolvePromise(res, resolve, reject) // 处理成功时结果
} catch(e) {
reject(e)
}
const p = new Mypromise((resolve, reject) => {
// throw new Error('executor错误')
resolve('CHENGGONG')
})
p.then(res=> {
console.log(res)
throw new Error('then中错误') // 如果then中发生了错误
}, err=> {
console.log(err + '---')
}).then(res => {
console.log(res)
}, err => {
console.log('捕获then')
console.log(err)
})
// 打印结果
//CHENGGONG
//捕获then
// Error: then中错误
关于then失败的链式调用
目前为止 then成功时 可以进行链式调用,并且可以捕获到执行器发生的错误和then成功时发生错误
那么失败我们还不能链式调用。 也没有捕获到then失败的发生错误
if(this.status === REJECTED) { // 如果失败了我们也应该去拿到失败回调的结果进行 通过resolvePromise, 解析失败的回调,并且用try cath捕获失败回调发生的错误
try {
let res = failureFn(this.errmessage ) // 执行失败的回调 参数是失败信息
resolvePromise(res, resolve, reject) // 处理成功时结果
} catch(e) {
reject(e)
}
}
const p = new Mypromise((resolve, reject) => {
// throw new Error('executor错误')
reject('失败了')
})
p.then(res=> {
console.log(res)
}, err=> {
console.log(err + '---')
return '111' // then失败回调return是一个字符串111
}).then(res => {
console.log(res)
}, err => {
console.log('捕获then')
console.log(err)
})
// ***失败链式调用,then返回的是一个普通值
// 打印结果
//失败了---
//111
const p = new Mypromise((resolve, reject) => {
// throw new Error('executor错误')
reject('失败了')
})
p.then(res=> {
console.log(res)
}, err=> {
console.log(err + '---')
return new MyPromise((resolve, reject) => { // then返回的是一个promsie
resolve('then返回的是一个promsie')
})
}).then(res => {
console.log(res)
}, err => {
console.log('捕获then')
console.log(err)
})
// // ***失败链式调用,then返回的是一个promsie
// 打印结果
//失败了---
//then返回的是一个promsie
// 捕获错误
p.then(res=> {
console.log(res)
}, err=> {
console.log(err + '---')
throw new Error('错误了') // then中抛出一个错误
}).then(res => {
console.log(res)
}, err => {
console.log('捕获then')
console.log(err) // 111
})
// 打印结果
//失败了---
//捕获then
//Error: 错误了
关于异步操作
此刻我们还没有处理异步的情况。如果then中的操作是异步操作呢
this.succcessCallback.push(successFn(this.response) )
this.failureCallback.push(failureFn(this.errmessage));
------------------
// 这里以前我们是通过push的方法存储回调 如果then中的异步,我们就要push 一个函数了。
this.succcessCallback.push(() => {
// 如果是成功去执行成功的代码
try {
let res = successFn(this.response) // 执行成功的回调 参数是成功的响应数据
resolvePromise(res, resolve, reject) // 处理成功时结果
} catch(e) {
reject(e)
}
})
this.failureCallback.push(() => {
try {
let res = failureFn(this.errmessage) // 执行成功的回调 参数是成功的响应数据
resolvePromise(res, resolve, reject) // 处理成功时结果
} catch(e) {
reject(e)
}
});
}
------------------
// resolve
while (this.succcessCallback.length) {
this.succcessCallback.shift()() // 此时这里就不用传递this.response
}
// reject 同理
while (this.failureCallback.length) {
this.failureCallback.shift()()
}
-------------------
p.then(res=> {
// console.log(res)
return new Mypromise((resolve, reject) => {
setTimeout(() => {
resolve('then中的异步操作')
}, 1000)
})
}, err=> {
console.log(err + '---')
throw new Error('错误了')
}).then(res => {
console.log(res)
}, err => {
console.log('捕获then')
console.log(err) // 111
})
// 打印结果
// then中的异步操作 1s后打印
promise的循`环调用
下面的代码发生了promise的循环调用。当我们用p2接受p1.then执行结果, 恰巧在p1.then中我们也return了p2那么就发生了promise的循环调用这是不允许的
const p1 = new Promise((resolve, reject) => {
resolve('1')
})
let p2 = p1.then(res= > {
return p2
})
p2.then(res=> res, err=> console.log(err))
// TypeError: Chaining cycle detected for promise
也就是说在promise中, then方法中会自动判断回调函数执行结果是否和then返回的结果一样
successFn() 就是回调执行结果
pr 就是then方法中返回的那个promise对象,
const pr = new Mypromise((resolve, reject) => {
// 当前状态成功了执行successFn
// 当前状态失败了执行 failureFn
if(this.status === FULFILLED) {
try {
let res = successFn(this.response) // 执行成功的回调 参数是成功的响应数据
resolvePromise(res, resolve, reject) // 处理成功时结果
} catch(e) {
reject(e)
}
}
// then中返回的promise 和 执行回调的结果promise 不能是一个同一个promise
function resolvePromise(returnP, res, resolve, reject) {
if (returnP === res) {
// 如果回调的promise 和 then中要返回的promise是同一个对象那么就发生了 循环调用。 直接return 阻止代码继续向下执行
return reject(new TypeError 'Chaining cycle detected for promise #<Promise>')
}
if (res instanceof Mypromise) {
// 执行结果是一个promise
// 调用then方法拿到执行结果如果成功执行resolve
// 失败就调用reject
res.then(value => resolve(value), err => reject(err))
} else {
// 普通值直接调用resolve方法
resolve(res)
}
}
// 在promise处理时要补一个实参就是pr
// 但是此时我们能拿到pr吗?
// 所以这里也需要加入异步操作
resolvePromise(pr, res, resolve, reject) // 处理成功时结果
const pr = new Mypromise((resolve, reject) => {
// 当前状态成功了执行successFn
// 当前状态失败了执行 failureFn
if(this.status === FULFILLED) {
try {
let res = successFn(this.response) // 执行成功的回调 参数是成功的响应数据
resolvePromise(res, resolve, reject) // 处理成功时结果
} catch(e) {
reject(e)
}
}
then的穿透
then中也可以不传递,如果没有传参可以进行then的调用
const p1 = new Promise((resolve, reject) => {
resolve('1')
})
p1.then()
.then()
.then(val => console.log(val))
// 因此我可以进步补参的方法
then = (successFn, failureFn) => {
successFn ? successFn : value => value
}
目前位置已经实现了promise的大部分功能
全部代码
// 首先设置三种状态常量
const PENDDING = 'pendding';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected'
class Mypromise {
constructor(executor) {
// new promise是会立即执行执行器,并且接受两个参数, resolve函数和reject函数
// 执行器执行时发生了错误用try cathch去捕获执行器执行
try {
executor(this.resolve, this.reject)
} catch (e) {
// 如果有错误直接执行reject
this.reject(e)
}
}
status = PENDDING;
response = undefined // 定义一个成功的响应值
errmessage = undefined // 失败的信息
// 首先我们用属性succcessCallback存储successFn 和 failureCallback存储failureFn
succcessCallback = [];
failureCallback = [];
// resolve是一个函数, 参数是响应值
resolve = (response) => {
if(this.status !== PENDDING ) return
this.status = FULFILLED;
this.response = response; // 缓存成功消息
// 当异步操作2s后执行到resolve的时候 如果succcessCallback 存在那么执行succcessCallback
//this.succcessCallback && this.succcessCallback(this.response)
while (this.succcessCallback.length) {
this.succcessCallback.shift()()
}
}
// reject也是一个函数, 参数是错误消息
reject= (errmessage) => {
if(this.status !== PENDDING ) return
this.status = REJECTED;
this.errmessage = errmessage // 缓存失败信息
// 当异步操作2s后执行到reject的时候 如果failureCallback 存在那么执行failureCallback
//this.failureCallback && this.failureCallback (this.errmessage )
while (this.failureCallback.length) {
this.failureCallback.shift()()
}
}
// then方法
then = (successFn, failureFn) => {
successFn = successFn ? successFn : value => value // 补参如果有参数就用 如果没有参数就是一个函数
// 获取到promise
let pr = new Mypromise((resolve, reject) => {
// 当前状态成功了执行successFn
// 当前状态失败了执行 failureFn
if(this.status === FULFILLED) {
// 加入异步代码让它在pr生成后去用pr
setTimeout(() => {
// then中发生了错误 也用try catch捕获
try {
let res = successFn(this.response) // 执行成功的回调 参数是成功的响应数据
resolvePromise(pr, res, resolve, reject) // 处理成功时结果
} catch(e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
// then中发生了错误 也用try catch捕获
try {
let res = failureFn(this.errmessage) // 执行失败的回调 参数是失败的信息
resolvePromise(pr, res, resolve, reject) // 处理失败时结果
} catch(e) {
reject(e)
}
}, 0)
} else {
// 如果是pendding状态我们首先储存succcessCallback 和 failureCallback
// this.succcessCallback.push(successFn);
// this.failureCallback.push(failureFn);
// 这里以前我们是通过push的方法存储回调 如果then中的异步,我们就要push 一个函数了。
this.succcessCallback.push(() => {
// 如果是成功去执行成功的代码
setTimeout(() => {
// then中发生了错误 也用try catch捕获
try {
let res = successFn(this.response) // 执行成功的回调 参数是成功的响应数据
resolvePromise(pr, res, resolve, reject) // 处理成功时结果
} catch(e) {
reject(e)
}
}, 0)
})
this.failureCallback.push(() => {
setTimeout(() => {
// then中发生了错误 也用try catch捕获
try {
let res = failureFn(this.errmessage) // 执行失败的回调 参数是失败的信息
resolvePromise(pr, res, resolve, reject) // 处理失败时结果
} catch(e) {
reject(e)
}
}, 0)
});
}
})
return pr; // 返回一个promise
}
}
// res是successFn执行的结果, resolve是成功的回调, reject是结束的回调
function resolvePromise(returnP, res, resolve, reject) {
if (returnP === res) {
// 如果回调的promise 和 then中要返回的promise是同一个对象那么就发生了 循环调用。 直接return 阻止代码继续向下执行
return reject(new TypeError ('Chaining cycle detected for promise #<Promise>'))
}
if (res instanceof Mypromise) {
// 执行结果是一个promise
// 调用then方法拿到执行结果如果成功执行resolve
// 失败就调用reject
res.then(value => resolve(value), err => reject(err))
} else {
// 普通值直接调用resolve方法
resolve(res)
}
}
const p = new Mypromise((resolve, reject) => {
// throw new Error('executor错误')
resolve('成功')
})
let pp = p.then(
res => {
return pp
}
)
pp.then(res=> res, err => {console.log(err)})
// 打印TypeError: Chaining cycle detected for promise #<Promise>