一、关于promise的架子
根据Promises/A+写了一个关于promise的架子,这个架子将除了task和#Resolve以外的所有事情都做了。因为task运行时,promise一定已经完成了,所以task会很好写。可以先写task,最后再尝试#Resolve。当被要求手写一个promise时,这个架子会很有用。
class _Promise {
#state = 'pending'
#result = undefined
#resolve
#reject
constructor(callback) {
let setState = (state, result) => {
this.#state = state
this.#result = result
setState = () => { }
this.#run()
}
this.#resolve = value => setState('fulfilled', value)
this.#reject = reason => setState('rejected', reason)
callback(this.#resolve, this.#reject)
}
// 任务队列,promise到达最终状态前的所有任务都在其中
#task_queue = []
// 取出任务并执行
#run() {
let task
while (task = this.#task_queue.shift()) task()
}
then(onFulfilled, onRejected) {
const promise2 = new _Promise((resolve, reject) => {
// task
let task = () => { }
this.#state === 'pending' ? this.#task_queue.push(task) : task()
})
// then方法返回一个promise
return promise2
}
// #Resolve,task会用到
#Resolve(promise, x) { }
}
二、完成版
class _Promise {
#state = 'pending'
#result = undefined
#resolve
#reject
constructor(callback) {
let setState = (state, result) => {
this.#state = state
this.#result = result
setState = () => { }
this.#run()
}
this.#resolve = value => setState('fulfilled', value)
this.#reject = reason => setState('rejected', reason)
callback(this.#resolve, this.#reject)
}
#task_queue = []
#run() {
let task
while (task = this.#task_queue.shift()) task()
}
then(onFulfilled, onRejected) {
const promise2 = new _Promise((resolve, reject) => {
let task = () => {
if (this.#state === 'fulfilled') {
if (typeof onFulfilled === 'function') {
queueMicrotask(() => {
try {
const x = onFulfilled(this.#result)
this.#Resolve(promise2, x)
} catch (error) {
reject(error)
}
})
} else resolve(this.#result)
}
if (this.#state === 'rejected') {
if (typeof onRejected === 'function') {
queueMicrotask(() => {
try {
const x = onRejected(this.#result)
this.#Resolve(promise2, x)
} catch (error) {
reject(error)
}
})
} else reject(this.#result)
}
}
this.#state === 'pending' ? this.#task_queue.push(task) : task()
})
return promise2
}
#Resolve(promise, x) {
if (promise === x) promise.#reject(new TypeError('promise 和 x 不能引用同一对象'))
if (x instanceof _Promise) x.then(promise.#resolve, promise.#reject)
if (typeof x === 'object' || typeof x === 'function') {
let then
try {
then = x.then
} catch (error) {
promise.#reject(error)
}
if (typeof then === 'function') {
let used = false
let resolvePromise = y => {
if (used) return
this.#Resolve(promise, y)
used = true
}
let rejectPromise = r => {
if (used) return
promise.#reject(r)
used = true
}
try {
x.then(resolvePromise, rejectPromise)
} catch (error) {
if (used) return
promise.#reject(error)
}
} else promise.#resolve(x)
} else promise.#resolve(x)
}
}
三、测试then
2.1
承诺必须处于以下三种状态之一:pending, fulfilled, rejected。
2.1.1
待处理时,promise:
2.1.1.1
可能会转换(过渡)为“已满足”或“已拒绝”状态。
<script src="./_Promise.js"></script>
<script>
let p1 = new _Promise((resolve) => {
setTimeout(() => {
resolve()
console.log(p1);
console.log('p2======')
let p2 = new _Promise((resolve,reject) => {
setTimeout(() => {
reject()
console.log(p2);
})
})
console.log(p2);
})
})
console.log('p1======')
console.log(p1);
</script>
2.1.2
实现(fulfilled)时的promise:
2.1.2.1
不得过渡到任何其他状态。
<script src="./_Promise.js"></script>
<script>
let p1 = new _Promise((resolve, reject) => {
setTimeout(() => {
resolve()
console.log('实现', p1);
setTimeout(() => {
reject()
console.log('修改状态', p1);
})
})
})
</script>
2.1.2.2
必须有一个值,该值不得更改。
<script src="./_Promise.js"></script>
<script>
let p1 = new _Promise((resolve, reject) => {
resolve('1:初次传值')
resolve('2:修改传值')
reject('3:修改传值')
})
setTimeout(() => {
console.log(p1);
})
</script>
2.1.3
当被拒绝(rejected)时,promise:
2.1.3.1
不得过渡到任何其他状态。
<script src="./_Promise.js"></script>
<script>
let p1 = new _Promise((resolve, reject) => {
setTimeout(() => {
reject()
console.log('拒绝', p1);
setTimeout(() => {
resolve()
console.log('修改状态', p1);
})
})
})
</script>
2.1.3.2
必须有一个理由,这个理由不能改变。
<script src="./_Promise.js"></script>
<script>
let p1 = new _Promise((resolve, reject) => {
reject('1:初次给出理由')
reject('2:修改理由')
resolve('3:修改理由')
})
setTimeout(() => {
console.log(p1);
})
</script>
2.2
promise 的 then
方法接受两个参数:
promise.then(onFulfilled, onRejected)
2.2.1
onFulfilled
和 onRejected
都是可选参数:
2.2.1.1
如果 onFulfilled
不是一个函数,则必须忽略它。
<script src="./_Promise.js"></script>
<script>
let p = new _Promise((resolve, reject) => {
resolve('value')
})
p.then('不是函数')
console.log('正常运行');
console.log(p);
</script>
2.2.1.2
如果 onRejected
不是一个函数,则必须忽略它。
<script src="./_Promise.js"></script>
<script>
let p = new _Promise((resolve, reject) => {
reject('reason')
})
p.then(undefined,'不是函数')
console.log('正常运行');
console.log(p);
</script>
2.2.2
如果 onFulfilled
是一个函数:
2.2.2.1
它必须在 promise
实现后调用,并将 promise
的值作为其第一个参数。
<script src="./_Promise.js"></script>
<script>
let p = new _Promise((resolve, reject) => {
setTimeout(() => {
console.log('实现前');
resolve('value')
console.log('实现后');
}, 1000)
})
p.then((res) => {
console.log('被调用', res);
})
</script>
2.2.2.2
在promise实现之前,绝不能召唤它。
<script src="./_Promise.js"></script>
<script>
let p = new _Promise((resolve, reject) => {
setTimeout(() => {
console.log('实现前');
resolve('value')
console.log('实现后');
}, 1000)
})
p.then((res) => {
console.log('被调用', res);
})
</script>
2.2.2.3
不得多次调用它。
<script src="./_Promise.js"></script>
<script>
let p = new _Promise((resolve, reject) => {
resolve('实现1')
resolve('实现2')
resolve('实现3')
})
let i = 1
p.then((value) => {
console.log('被调用%d次:%s', i++,value);
})
</script>
2.2.3
如果 onRejected
是一个函数,
2.2.3.1
它必须在 promise
被拒绝后调用,并将 promise
的理由作为其第一个参数。
<script src="./_Promise.js"></script>
<script>
let p = new _Promise((resolve, reject) => {
setTimeout(() => {
console.log('拒绝前');
reject('reason')
console.log('拒绝后');
}, 1000)
})
p.then(undefined,(reason) => {
console.log('被调用', reason);
})
</script>
2.2.3.2
在 Promise
被拒绝之前,不得调用它。
<script src="./_Promise.js"></script>
<script>
let p = new _Promise((resolve, reject) => {
setTimeout(() => {
console.log('拒绝前');
reject('reason')
console.log('拒绝后');
}, 1000)
})
p.then(undefined,(reason) => {
console.log('被调用', reason);
})
</script>
2.2.3.3
不得多次调用它。
<script src="./_Promise.js"></script>
<script>
let p = new _Promise((resolve, reject) => {
reject('拒绝1')
reject('拒绝2')
reject('拒绝3')
})
let i = 1
p.then(undefined,(reason) => {
console.log('被调用%d次:%s', i++,reason);
})
</script>
2.2.4
在执行上下文堆栈仅包含平台代码之前,不得调用 onFulfilled
或 onRejected。
let p1 = new _Promise((resolve, reject) => {
resolve('value')
})
console.log('当前执行中%d...', 1);
p1.then((value) => {
console.log('实现:%s', value);
})
console.log('当前执行中%d...', 2);
let p2 = new _Promise((resolve, reject) => {
reject('value')
})
console.log('当前执行中%d...', 3);
p2.then(undefined, (reason) => {
console.log('拒绝:%s', reason);
})
console.log('当前执行中%d...', 4);
console.log('当前执行中%d...', 5);
console.log('执行完毕%d:______', 6);
</script>
2.2.5
onFulfilled
和 onRejected
必须作为函数调用(即没有this值)。
<script src="./_Promise.js"></script>
<!-- 非严格模式 -->
<script>
console.log(
"%c 非严格模式",
"color: yellow; font-style: italic; background-color: blue;padding: 2px",
);
let p1 = new _Promise((resolve, reject) => {
resolve()
})
p1.then(() => {
console.log('onFulfilled的%cthis:', 'color:blue');
console.log(this);
})
let p2 = new _Promise((resolve, reject) => {
reject()
})
p2.then(undefined, (reason) => {
console.log('onRejected的%cthis:', 'color:blue');
console.log(this);
})
</script>
<!-- 严格模式 -->
<script type="module">
console.log(
"%c 严格模式",
"color: yellow; font-style: italic; background-color: red;padding: 2px",
);
let p1 = new _Promise((resolve, reject) => {
resolve()
})
p1.then(() => {
console.log('onFulfilled的%cthis:', 'color:blue');
console.log(this);
})
let p2 = new _Promise((resolve, reject) => {
reject()
})
p2.then(undefined, (reason) => {
console.log('onRejected的%cthis:', 'color:blue');
console.log(this);
})
</script>
2.2.6
then可能会在同一个 promise 上多次调用。
2.2.6.1
如果当 promise
被实现,所有相应的 onFulfilled
回调必须按照其原始调用的顺序执行到then
。
<script src="./_Promise.js"></script>
<script>
let p = new _Promise((resolve, reject) => {
setTimeout(() => {
p.then(() => { console.log('第%d次调用then', 3); })
p.then(() => { console.log('第%d次调用then', 4); })
resolve()
p.then(() => { console.log('第%d次调用then', 5); })
p.then(() => { console.log('第%d次调用then', 6); })
}, 500);
})
p.then(() => { console.log('第%d次调用then', 1); })
p.then(() => { console.log('第%d次调用then', 2); })
</script>
2.2.6.2
如果当 promise
被拒绝时,所有相应的 onRejected
回调必须按照其原始调用的顺序执行到then
。
<script src="./_Promise.js"></script>
<script>
let p = new _Promise((resolve, reject) => {
setTimeout(() => {
p.then(undefined,() => { console.log('第%d次调用then', 3); })
p.then(undefined,() => { console.log('第%d次调用then', 4); })
reject()
p.then(undefined,() => { console.log('第%d次调用then', 5); })
p.then(undefined,() => { console.log('第%d次调用then', 6); })
}, 500);
})
p.then(undefined,() => { console.log('第%d次调用then', 1); })
p.then(undefined,() => { console.log('第%d次调用then', 2); })
</script>
2.2.7
then必须返回一个 promise。
promise2 = promise1.then(onFulfilled, onRejected);
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve,reject)=>{})
const promise2 = promise1.then();
console.log(promise2);
</script>
2.2.7.1
如果 onFulfilled
或 onRejected
返回值 x
,则运行 Promise 解析过程 [[Resolve]](promise2, x)。转到:
四(测试#Resolve)
2.2.7.2
如果 onFulfilled
或 onRejected
抛出异常 e
,则必须以 e
为原因拒绝 promise2
。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const promise2 = promise1.then(() => {
throw new Error('onFulfilled:异常')
});
promise2.then(undefined, console.log)
const promise3 = new _Promise((resolve, reject) => { reject() })
const promise4 = promise3.then(undefined,() => {
throw new Error('onRejected:异常')
});
promise4.then(undefined, console.log)
</script>
2.2.7.3
如果 onFulfilled
不是函数,并且 promise1
已实现,则 promise2
必须使用与 promise1
相同的值实现。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => {
setTimeout(() => {
resolve('实现,value')
console.log('promise2',promise2);
})
})
const promise2 = promise1.then('我(onFulfilled)不是函数');
</script>
2.2.7.4
如果 onRejected
不是函数并且 promise1
被拒绝,则必须以与 promise1
相同的原因拒绝 promise2
。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => {
setTimeout(() => {
reject('拒绝,reason')
console.log('promise2',promise2);
})
})
const promise2 = promise1.then(undefined,'我(onRejected)不是函数');
</script>
四、测试#Resolve
2.3.1
如果 promise
和 x
引用同一对象,则拒绝 promise
,并给出 TypeError
作为原因。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const promise2 = promise1.then(() => promise2);
setTimeout(() => { console.log(promise2) })
const promise3 = new _Promise((resolve, reject) => { reject() })
const promise4 = promise3.then(undefined, () => promise4);
setTimeout(() => { console.log(promise4) })
</script>
2.3.2
如果 x
是 promise,则采用其状态 :
2.3.2.1
如果 x
处于待处理状态,则 promise
必须保持待处理状态,直到 x
被实现或拒绝。
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const x = new _Promise(()=>{})
const promise = promise1.then(() => x);
console.log(promise);
</script>
2.3.2.2
如果当 x
实现时,以相同的值实现promise。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const x = new _Promise((resolve) => { resolve('x实现,value') })
const promise = promise1.then(() => x);
setTimeout(() => { console.log(promise); })
</script>
2.3.2.3
如果当 x
被拒绝时,以同样的原因拒绝 promise
。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const x = new _Promise((resolve,reject) => { reject('x拒绝,reason') })
const promise = promise1.then(() => x);
setTimeout(() => { console.log(promise); })
</script>
2.3.3
否则,如果 x
是对象或函数
2.3.3.1
设 then
为 x.then
。
2.3.3.2
如果检索属性 x.then
导致抛出异常 e
,则拒绝以 e
为原因的 promise
。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const x = Object.defineProperty({}, 'then', {
get() {
throw new Error('不能访问then')
}
})
const promise = promise1.then(() => x);
setTimeout(() => { console.log(promise); })
</script>
2.3.3.3
如果 then
是一个函数,则使用 x
调用它
,第一个参数 resolvePromise
,第二个参数 rejectPromise
,其中:
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const x = {
then(resolvePromise, rejectPromise) {
console.log('resolvePromise', resolvePromise);
console.log('rejectPromise', rejectPromise);
}
}
const promise = promise1.then(() => x);
</script>
2.3.3.3.1
如果当使用值 y
调用 resolvePromise
,则运行 [[Resolve]](promise, y)。
2.3.3.3.2
如果当使用原因 r
调用 rejectPromise
,则使用 r
拒绝 promise
。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const x = {
then(resolvePromise, rejectPromise) {
rejectPromise('拒绝,r')
}
}
const promise = promise1.then(() => x);
setTimeout(() => { console.log(promise); })
</script>
2.3.3.3.3
如果同时调用了 resolvePromise
和 rejectPromise
,或者对同一参数进行了多次调用,则第一个调用优先,并且将忽略任何进一步的调用。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const x = {
then(resolvePromise, rejectPromise) {
resolvePromise('第1个调用,实现,y')
rejectPromise('第2个调用,拒绝,r')
resolvePromise('第3个调用,实现,y')
rejectPromise('第4个调用,拒绝,r')
}
}
const promise = promise1.then(() => x);
setTimeout(() => { console.log(promise); })
</script>
2.3.3.3.4
如果调用then抛出异常 e
,
2.3.3.3.4.1
如果已调用 resolvePromise
或 rejectPromise
,请忽略它。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const x = {
then(resolvePromise, rejectPromise) {
resolvePromise('已调用resolvePromise') //rejectPromise同理
throw new Error('异常')
}
}
const promise = promise1.then(() => x);
setTimeout(() => { console.log(promise); })
</script>
2.3.3.3.4.2
否则,拒绝以 e
为原因的 promise
。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const x = {
then(resolvePromise, rejectPromise) {
throw new Error('异常')
resolvePromise('在异常后')
}
}
const promise = promise1.then(() => x);
setTimeout(() => { console.log(promise); })
</script>
2.3.3.4
如果 then
不是一个函数,则用 x
实现promise
。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const x = {
name:'x',
then: 'x.then:我不是函数'
}
const promise = promise1.then(() => x);
setTimeout(() => { console.log(promise); })
</script>
2.3.4
如果 x
不是对象或函数,则用 x
实现承诺
。
<script src="./_Promise.js"></script>
<script>
const promise1 = new _Promise((resolve, reject) => { resolve() })
const x = 'x:我不是对象,也不是函数'
const promise = promise1.then(() => x);
setTimeout(() => { console.log(promise); })
</script>