1 代码实现
/*
自定义Promise
*/
(function (window) {
/*
Promise构造函数
excutor: 内部同步执行的函数 (resolve, reject) => {}
*/
function Promise(excutor) {
const self = this
self.status = 'pending' // 状态值, 初始状态为pending, 成功了变为resolved, 失败了变为rejected
self.data = undefined // 用来保存成功value或失败reason的属性
self.callbacks = [] // 用来保存所有待调用的包含onResolved和onRejected回调函数的对象的数组
/*
异步处理成功后应该调用的函数;value: 将交给onResolve()的成功数据
*/
function resolve(value) {
// 如果当前不是pending, 直接结束
if(self.status!==pending) {
return
}
// 立即更新状态, 保存数据
self.status = 'resolved'
self.data = value
// 如果有待执行的callback函数,立即异步执行回调函数onResolved
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach(obj => {
obj.onResolved(value)
})
})
}
}
/*
异步处理失败后应该调用的函数;reason: 将交给onRejected()的失败数据
*/
function reject(reason) {
// 如果当前不是pending, 直接结束
if(self.status!==pending) {
return
}
// 立即更新状态, 保存数据
self.status = 'rejected'
self.data = reason
// 如果有待执行的callback函数,立即异步执行回调函数onRejected
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach(obj => {
obj.onRejected(value)
})
})
}
}
try {// 立即同步调用excutor()处理
excutor(resolve, reject)
} catch (error) { // 如果出了异常, 直接失败
reject(error)
}
}
/*
1.为promise指定成功/失败的回调函数;函数的返回值是一个新的promise对象
*/
Promise.prototype.then = function (onResolved, onRejected) {
// 保存promise对象
const self = this
// 如果成功/失败的回调函数不是function, 指定一个默认实现的函数
onResolved = typeof onResolved === 'function' ? onResolved : value => value//向后传递成功的value
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}//向后传递失败的reason(实现错误传透)
// 返回一个新的promsie对象:三种状态
return new Promise((resolve, reject) => {
// 调用指定的回调函数,根据执行结果改变return的promise的状态/数据
function handle (callback) {
try {
const x = callback(self.data)// 用x变量存储onResolved()的返回值
//a.如果回调函数返回的是promise,return的promise的结果就是这个promise的结果
if (x instanceof Promise) {
x.then(resolve, reject)
//b.如果回调函数返回的不是promise,return的promise会成功,返回value
} else {
resolve(x)
}
//c. 如果抛出异常,return的promise就会失败,reason就是error
} catch (error) {
reject(error)
}
}
if (self.status === 'resolved') {
// 异步执行onResolved
setTimeout(() => {
handle(onResolved)
})
} else if (self.status === 'rejected') {
// 异步执行onRejected
setTimeout(() => {
handle(onRejected)
})
} else {
// 保存待处理的回调函数
self.callbacks.push({
onResolved (value) {
handle(onResolved)
},
onRejected(value) {
handle(onRejected)
}
})
}
})
}
/*
2.为promise指定失败的回调函数;是then(null, onRejected)的语法糖
*/
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected)
}
/*
3.返回一个指定了成功value的promise对象;value: 一般数据或promise
*/
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
// 如果传入的是promise对象, 将此promise的结果值作为返回promise的结果值
if (value instanceof Promise) {
value.then(resolve, reject)//结果需要通过then取到
// 将value作为返回promise的成功结果值
} else {
resolve(value)
}
})
}
/*
4.返回一个指定了失败reason的promise对象;reason: 一般数据/error
*/
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
// 将传入的参数作为返回promise的失败结果值
reject(reason)
})
}
/*
5.返回一个新的promise对象, 只有promises中所有promise都产生成功value时, 才最终成功, 只要有一个失败就直接失败
*/
Promise.all = function (promises) {
// 返回一个新的promise
return new Promise((resolve, reject) => {
// 已成功的数量
let resolvedCount = 0
// 待处理的promises数组的长度
const promisesLength = promises.length
// 准备一个保存成功值的数组(保证结果按照数组的顺序)
const values = new Array(promisesLength)
// 遍历每个待处理的promise
for (let i = 0; i < promisesLength; i++) {
// promises中元素可能不是一个promise, 需要用resolve包装一下
Promise.resolve(promises[i]).then(
value => {
// 成功当前promise成功的值到对应的下标
values[i] = value
// 成功的数量加1
resolvedCount++
// 一旦全部成功
if(resolvedCount===promisesLength) {
// 将所有成功值的数组作为返回promise对象的成功结果值
resolve(values)
}
},
reason => {
// 一旦有一个promise产生了失败结果值, 将其作为返回promise对象的失败结果值
reject(reason)
}
)
}
})
}
/*
6.返回一个 promise,一旦某个promise解决或拒绝, 返回的 promise就会解决或拒绝。
*/
Promise.race = function (promises) {
// 返回新的promise对象
return new Promise((resolve, reject) => {
// 遍历所有promise
for (var i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(
(value) => { // 只要有一个成功了, 返回的promise就成功了
resolve(value)
},
(reason) => { // 只要有一个失败了, 返回的结果就失败了
reject(reason)
}
)
}
})
}
/*
7.返回一个延迟指定时间才确定结果的promise对象
*/
Promise.resolveDelay = function (value, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (value instanceof Promise) { // 如果value是一个promise, 取这个promise的结果值作为返回的promise的结果值
value.then(resolve, reject) // 如果value成功, 调用resolve(val), 如果value失败了, 调用reject(reason)
} else {
resolve(value)
}
}, time);
})
}
/*
8.返回一个延迟指定时间才失败的Promise对象。
*/
Promise.rejectDelay = function (reason, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(reason)
}, time)
})
}
// 暴露构造函数
window.Promise = Promise
})(window)
2 逻辑分析
Promise:
- 同步调用excutor,用try-catch处理。
- 调用resolve,更新状态并保存数据,异步执行回调函数onResolved。
- 调用reject,执行的是onRejected
Promise.prototype.then:
- 根据status,来决定是保存还是调用异步回调函数。
- 根据回调函数的返回结果,返回新的promise对象。
a.如果回调函数返回的是promise,return的promise的结果就是这个promise的结果
b.如果回调函数返回的不是promise,return的promise会成功,返回value
c. 如果抛出异常,return的promise就会失败,reason就是error
Promise.prototype.catch:
是then(null, onRejected)的语法糖
Promise.resolve:
- 如果传入的是promise对象, 将此promise的结果值作为返回promise的结果值
- 如果传入的是非promise对象, 将value作为返回promise的成功结果值
Promise.reject:
将传入的参数作为返回promise的失败结果值
Promise.all:
遍历每个待处理的promises,成功将value存到到对应的下标,直到全部成功返回value;失败将reason返回。
Promise.race:
遍历每个待处理的promises,只要有一个成功了, 返回的promise就成功了;只要有一个失败了, 返回的结果就失败了
3 class版本
excutor定义改成constructor
原型上的直接定义方法,类上的加static
/*
自定义Promise构造函数模块
*/
(function (window) {
class Promise {
constructor (excutor) {
const self = this
// 1. 初始化属性
self.status = 'pending'
self.data = undefined
self.callbacks = []
// 2. 定义resolve和reject两个函数
/*
当异步处理成功后应该立即执行的函数
value: 需要传递给onResolved函数的成功的值
内部:
1. 同步修改状态和保存数据
2. 异步调用成功的回调函数
*/
function resolve(value) {
if (self.status !== 'pending') {
return
}
// 1. 同步修改状态和保存数据
self.status = 'resolved'
self.data = value
// 2. 异步调用成功的回调函数
setTimeout(() => {
self.callbacks.forEach(obj => {
obj.onResolved(value)
})
})
}
/*
当异步处理失败/异常时后应该立即执行的函数
reason: 需要传递给onRejected函数的失败的值
内部:
1. 同步修改状态和保存数据
2. 异步调用失败的回调函数
*/
function reject(reason) {
if (self.status !== 'pending') {
return
}
// 1. 同步修改状态和保存数据
self.status = 'rejected'
self.data = reason
// 2. 异步调用失败的回调函数
setTimeout(() => {
self.callbacks.forEach(obj => {
obj.onRejected(reason)
})
})
}
// 3. 执行excutor,并传入定义好的resolve和reject两个函数
try {
excutor(resolve, reject)
} catch (error) { // 如果excutor函数中抛出异常, 当前promise失败
reject(error)
}
}
/*
指定成功和失败后回调函数
函数的返回值是一个新的promise
*/
then (onResolved, onRejected) {
const self = this
// 如果onResolved/onRejected不是函数, 可它指定一个默认的函数
onResolved = typeof onResolved === 'function' ? onResolved : value => value // 指定返回的promise为一个成功状态, 结果值为 value
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
} // 指定返回的promise为一个失败状态, 结果值为reason
// 返回一个新的promise对象
return new Promise((resolve, reject) => {
/*
专门抽取的用来处理promise成功/失败结果的函数
callback: 成功/失败的回调函数
*/
function handle(callback) {
// 1. 抛出异常 ===> 返回的promise变为rejected
try {
const x = callback(self.data)
// 2. 返回一个新的promise ===> 得到新的promise的结果值作为返回的promise的结果值
if (x instanceof Promise) {
x.then(resolve, reject) // 一旦x成功了, resolve(value), 一旦x失败了: reject(reason)
} else {
// 3. 返回一个一般值(undefined) ===> 将这个值作为返回的promise的成功值
resolve(x)
}
} catch (error) {
reject(error)
}
}
if (self.status === 'resolved') { // 当前promise已经成功了
setTimeout(() => {
handle(onResolved)
})
} else if (self.status === 'rejected') { // 当前promise已经失败了
setTimeout(() => {
handle(onRejected)
})
} else { // 当前promise还未确定 pending
// 将onResolved和onRejected保存起来
self.callbacks.push({
onResolved(value) {
handle(onResolved)
},
onRejected(reason) {
handle(onRejected)
}
})
}
})
}
/*
方法返回一个Promise,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同
then()的语法糖
*/
catch (onRejected) {
return this.then(null, onRejected)
}
/*
返回一个以给定值解析后的Promise 对象
value也可能是一个promise
*/
static resolve (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) { // 如果value是一个promise, 取这个promise的结果值作为返回的promise的结果值
value.then(resolve, reject) // 如果value成功, 调用resolve(val), 如果value失败了, 调用reject(reason)
} else {
resolve(value)
}
})
}
/*
返回一个延迟指定时间才确定结果的promise对象
*/
static resolveDelay (value, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (value instanceof Promise) { // 如果value是一个promise, 取这个promise的结果值作为返回的promise的结果值
value.then(resolve, reject) // 如果value成功, 调用resolve(val), 如果value失败了, 调用reject(reason)
} else {
resolve(value)
}
}, time);
})
}
/*
返回一个带有拒绝原因reason参数的Promise对象。
*/
static reject (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
/*
返回一个延迟指定时间才失败的Promise对象。
*/
static rejectDelay = function (reason, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(reason)
}, time)
})
}
/*
返回一个 Promise 实例
只有当promises中所有的都成功了, 返回的promise才成功, 只要有一个失败, 返回的promise就失败了
*/
static all (promises) {
return new Promise((resolve, reject) => {
let resolvedCount = 0 // 用来保存已成功的个数
const promisesLength = promises.length // 所有待处理promise个数
const values = new Array(promisesLength) // 存储所有成功value的数组
promises.forEach((p, index) => {
(function (index) {
// promises中元素可能不是promise对象, 需要用resolve()包装一下
Promise.resolve(p).then(
value => {
values[index] = value // 保存到values中对应的下标
resolvedCount++
// 如果全部成功了, resolve(values)
if (resolvedCount === promisesLength) {
resolve(values)
}
},
reason => {
// 只要一个失败了, reject(reason)
reject(reason)
}
)
})(index)
})
})
}
/*
返回一个 promise,一旦某个promise解决或拒绝, 返回的 promise就会解决或拒绝。
*/
static race (promises) {
return new Promise((resolve, reject) => {// 返回新的promise对象
for (var i = 0; i < promises.length; i++) {// 遍历所有promise
Promise.resolve(promises[i]).then(
(value) => { // 只要有一个成功了, 返回的promise就成功了
resolve(value)
},
(reason) => { // 只要有一个失败了, 返回的结果就失败了
reject(reason)
}
)
}
})
}
}
// 向外暴露Promise
window.Promise = Promise
})(window)
4 其他编码
4.1 加载图片
function loadImg(src) {
const p = new Promise(
(resolve, reject) => {
const img = document.createElement('img')
img.onload = () => {
resolve(img)
}
img.onerror = () => {
const err = new Error(`图片加载失败 ${src}`)
reject(err)
}
img.src = src
}
)
return p
}
const url1 = 'https://img.mukewang.com/5a9fc8070001a82402060220-140-140.jpg'
const url2 = 'https://img3.mukewang.com/5a9fc8070001a82402060220-100-100.jpg'
//then/catch
loadImg(url1).then(img1 => {
console.log(img1.width)
return img1 // 普通对象
}).then(img1 => {
console.log(img1.height)
return loadImg(url2) // promise 实例
}).then(img2 => {
console.log(img2.width)
return img2
}).then(img2 => {
console.log(img2.height)
}).catch(ex => console.error(ex))
//async/await
!(async function(){
const img1=await loadImg(url1)
console.log(img1.height,img1.width)
const img2=await loadImg(url2)
console.log(img2.height,img2.width)
})()
4.2 读取文件
function getFile(fpath) {
const p = new Promise(
(resolve, reject) => {
fs.readFile(fpath,'utf8',(err,data)=>{
if(err) return reject(err)
resolve(data)
})
}
)
return p
}
//then/catch
getFile(url1).then(r1=> {
console.log(r1)
}).catch(ex => console.log(ex.message))
//async/await
!(async function(){
const r1=await getFile(url1)
console.log(r1)
const r2=await getFile(url2)
console.log(r2)
})()