function myPromise() {
let self = this; // 此处 this 代指myPromise 这个函数
self.status = 'pending' // pending => resolve/reject
let value = null // 成功时的参数
let reason = null // 失败时的参数
// 成功的回调
function resolve(value) {
}
// 失败的回调
function reject(reason) {
}
myPromise.prototype.then = function(onFulfilled, onRejected) {}
let demo = new myPromise((resolve, reject) => {
console.log('myPromise 完成')
})
这样呢,一个简单的 promise 框架就写好啦
function myPromise(excutor) {
...
// 4.添加执行器,立即执行
try {
excutor(resolve, reject)
} catch(err) {
reject(err)
}
}
function myPromise() {
...
// 成功的回调
function resolve(value) {
self.value = value
self.status = 'fulfilled'
}
// 失败的回调
function reject(reason) {
self.value = reason
self.status = 'rejected'
}
myPromise.prototype.then = function(onFulfilled, onRejected) {
// 状态改变 就会调用.then 方法,强制要求必须返回一个函数
onFulfilled = typeof onFulfilled === 'function' ?
onFulfilled : function(data) { resolve(data) }
onRejected = typeof onRejected === 'function' ?
onRejected : function(err) { throw err }
}
以上,就实现了一个 promise的基本功能 ,下面我们来执行一下 promise,看是否能正常打印
// 执行构造函数,1秒后输出1
let demo = new myPromise((resolve, reject) => {
console.log('myPromise 完成')
setTimeout(() => {
resolve(1)
}, 1000)
})
// 调用 promise
demo.then(res => console.log(res)
我们发现这个结果是不执行的
原因:
"demo.then()"方法是同步调用的,此时在 myPromise.prototype.then中打印 this.status 仍然为 pending 状态,失败成功函数都不会执行,所以 demo.then 方法中不执行
解决:
此时,我们就可以利用发布-订阅模式来解决此问题,在myPromise.prototype.then方法中,增加保存状态的操作,等到状态改变后再去执行
function myPromise() {
……
self.onFulfilledcallbacks = []
self.onRejectedcallbacks = []
}
myPromise.prototype.then = function(onFulfilled, onRejected) {
...
// 8 订阅的操作,先把成功和失败的状态存起来,状态是 pending时候不执行,直到变成 fulfilled 状态再去执行
let self = this
if (self.status === 'pending') {
self.onFulfilledcallbacks.push(onFulfilled)
self.onRejectedcallbacks.push(onRejected)
}
}
function myPromise(excutor) {
...
// 成功的回调
function resolve(value) {
// 5.只有 pending 等待状态才操作
if(self.status === 'pending') {
self.value = value
self.status = 'fulfilled'
// 9.状态改变 => 发布,将回调依次取出
self.onFulfilledcallbacks.forEach(item => item(value))
}
}
}
// 失败的回调
function reject(reason) {
if(self.status === 'pending') {
self.value = reason
self.status = 'rejected'
// 9.状态改变 => 发布,将回调依次取出
self.onRejectedcallbacks.forEach(item => item(reason))
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>手写 promise</title>
</head>
<body>
<h1>手写 Promise</h1>
<script>
// 1.基础架构
function myPromise(excutor) {
let self = this; // 此处 this 代指myPromise 这个函数
self.status = 'pending' // pending => resolve/reject
let value = null // 成功时的参数
let reason = null // 失败时的参数
// 成功的回调
function resolve(value) {
// 5.只有 pending 等待状态才操作
if(self.status === 'pending') {
self.value = value
self.status = 'fulfilled'
// 9.状态改变 => 发布,将回调依次取出
self.onFulfilledcallbacks.forEach(item => item(value))
}
console.log('resolve中的回调', self.status)
}
// 失败的回调
function reject(reason) {
if(self.status === 'pending') {
self.value = reason
self.status = 'rejected'
// 9.状态改变 => 发布,将回调依次取出
self.onRejectedcallbacks.forEach(item => item(reason))
}
}
// 7.发布订阅模式,支持异步操作
self.onFulfilledcallbacks = []
self.onRejectedcallbacks = []
// 4.添加执行器,立即执行
try {
excutor(resolve, reject)
} catch(err) {
reject(err)
}
}
// 2. then方法,定义在原型上
myPromise.prototype.then = function(onFulfilled, onRejected) {
// 6.状态改变 就会调用.then 方法,强制要求必须返回一个函数
onFulfilled = typeof onFulfilled === 'function' ?
onFulfilled : function(data) { resolve(data) }
onRejected = typeof onRejected === 'function' ?
onRejected : function(err) { throw err }
// 未添加发布订阅模式(步骤7)时,状态改变之后,同步去调用 then(demo.then) 方法,但此处 status 仍为 pending,既不会成功也不会失败,所以不会去执行 resolve 方法,状态不同步,所以下方 demo.then 方法不执行
console.log('同步then 中状态', this.status)
// 8 订阅的操作,先把成功和失败的状态存起来,状态是 pending时候不执行,直到变成 fulfilled 状态再去执行
let self = this
if (self.status === 'pending') {
self.onFulfilledcallbacks.push(onFulfilled)
self.onRejectedcallbacks.push(onRejected)
}
}
// 3.构造函数立即执行
let demo = new myPromise((resolve, reject) => {
console.log('myPromise 完成')
setTimeout(() => {
resolve(1)
}, 1000)
})
demo.then(res => {
console.log('demo.then 的执行结果', res)
})
</script>
</body>
</html>
链式调用需要明确以下几点
1).then 中,可以通过把值传给下一步=> 给页面使用
2).也可以返回一个新的 promise,传给下一步
3).为了保证链式调用的实现,上一次then不管成功还是失败,都会把参数作为下一次 then 中成功的参数
if (self.status === 'fulfilled') {
return new myPromise((resolve, reject) => { // 返回一个 promise
try {
// 重点
// 判断成功的回调是否出现在 myPromise构造函数中
// instanceof运算符测试构造函数的属性是否出现在prototype对象的原型链中的任何位置
let x = onFulfilled(self.value)
// 如果出现就返回新的 Promise.then 否则返回 promise
x instanceof myPromise ? x.then(resolve, reject): resolve(x)
} catch(err) {
reject(err)
}
})
}
11.完善rejected\pending 状态下的链式调用
if (self.status === 'rejected') {
return new myPromise((resolve, reject) => {
try {
let x = onRejected(self.reason)
x instanceof myPromise ? x.then(resolve, reject): resolve(x)
} catch(err) {
reject(err)
}
})
}
if (self.status === 'pending') {
// self.onFulfilledcallbacks.push(onFulfilled)
// self.onRejectedcallbacks.push(onRejected)
return new myPromise((resolve, reject) => {
self.onFulfilledcallbacks.push(() => {
let x = onFulfilled(self.value)
x instanceof myPromise ? x.then(resolve, reject) : resolve(x)
})
self.onRejectedcallbacks.push(() => {
let x = onFulfilled(self.reason)
x instanceof myPromise ? x.then(resolve, reject) : resolve(x)
})
})
}
其实就是 then 方法的简化,调用 then 方法,成功函数传入 null,只传入失败函数并执行
myPromise.prototype.catch = function(fn) {
return this.then(null, fn)
}
然后,我们改写一下调用方法
let demo = new myPromise((resolve, reject) => {
console.log('myPromise 完成')
setTimeout(() => {
let obj = {age: 18}
resolve(obj)
}, 1000)
})
demo.then(res => {
let obj = {name: '小明'}
console.log('第一次调用 then', res)
return {...obj, ...res};
}).then(data => {
console.log('第二次调用 then', data)
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>手写 promise</title>
</head>
<body>
<h1>手写 Promise</h1>
<script>
// 1.基础架构
function myPromise(excutor) {
let self = this; // 此处 this 代指myPromise 这个函数
self.status = 'pending' // pending => resolve/reject
let value = null // 成功时的参数
let reason = null // 失败时的参数
// 成功的回调
function resolve(value) {
// 5.只有 pending 等待状态才操作
if(self.status === 'pending') {
self.value = value
self.status = 'fulfilled'
// 9.状态改变 => 发布,将回调依次取出
self.onFulfilledcallbacks.forEach(item => item(value))
}
console.log('resolve中的回调', self.status)
}
// 失败的回调
function reject(reason) {
if(self.status === 'pending') {
self.value = reason
self.status = 'rejected'
// 9.状态改变 => 发布,将回调依次取出
self.onRejectedcallbacks.forEach(item => item(reason))
}
}
// 7.发布订阅模式,支持异步操作
self.onFulfilledcallbacks = []
self.onRejectedcallbacks = []
// 4.添加执行器,立即执行
try {
excutor(resolve, reject)
} catch(err) {
reject(err)
}
}
// 2. then方法,定义在原型上
myPromise.prototype.then = function(onFulfilled, onRejected) {
// 6.状态改变 就会调用.then 方法,强制要求必须返回一个函数
onFulfilled = typeof onFulfilled === 'function' ?
onFulfilled : function(data) { resolve(data) }
onRejected = typeof onRejected === 'function' ?
onRejected : function(err) { throw err }
// 未添加发布订阅模式(步骤7)时,状态改变之后,同步去调用 then(demo.then) 方法,但此处 status 仍为 pending,既不会成功也不会失败,所以不会去执行 resolve 方法,状态不同步,所以下方 demo.then 方法不执行
console.log('同步then 中状态', this.status)
// 8 订阅的操作,先把成功和失败的状态存起来,状态是 pending时候不执行,直到变成 fulfilled 状态再去执行
let self = this
if (self.status === 'pending') {
// self.onFulfilledcallbacks.push(onFulfilled)
// self.onRejectedcallbacks.push(onRejected)
return new myPromise((resolve, reject) => {
// 11.改写 pending 方法
self.onFulfilledcallbacks.push(() => {
let x = onFulfilled(self.value)
x instanceof myPromise ? x.then(resolve, reject) : resolve(x)
})
self.onRejectedcallbacks.push(() => {
let x = onFulfilled(self.reason)
x instanceof myPromise ? x.then(resolve, reject) : resolve(x)
})
})
}
// 10.链式调用
//(1)then 中,可以通过把值传给下一步=> 给页面使用
// (2)也可以返回一个新的 promise,传给下一步
// (3)为了保证链式调用的实现,上一次then不管成功还是失败,都会把参数作为下一次 then 中成功的参数
//
if (self.status === 'fulfilled') {
return new myPromise((resolve, reject) => {
try {
let x = onFulfilled(self.value)
x instanceof myPromise ? x.then(resolve, reject): resolve(x)
} catch(err) {
reject(err)
}
})
}
if (self.status === 'rejected') {
return new myPromise((resolve, reject) => {
try {
let x = onRejected(self.reason)
x instanceof myPromise ? x.then(resolve, reject): resolve(x)
} catch(err) {
reject(err)
}
})
}
}
// 12.catch方法
myPromise.prototype.catch = function(fn) {
return this.then(null, fn)
}
// 3.构造函数立即执行
let demo = new myPromise((resolve, reject) => {
console.log('myPromise 完成')
setTimeout(() => {
let obj = {age: 18}
resolve(obj)
}, 1000)
})
demo.then(res => {
let obj = {name: '小明'}
console.log('第一次调用 then', res)
return {...obj, ...res};
}).then(data => {
console.log('第二次调用 then', data)
})
</script>
</body>
</html>