very-simple-promise,包含了不完善的单元测试❤️.react
代码君的自白git
这篇的文章主要参考了上面的博客,谢谢他的帮助🙏。github
Promises/A+规范, 下面👇是对规范的内容的部分翻译。英文比较烂,不喜欢的能够不看。c#
承诺必须知足三种状态, pending(等处理), fulfilled(履行), rejected(拒绝)数组
promise的then方法接受两个参数promise
promise.then(onFulfilled, onRejected)
复制代码
promise2 = promise1.then(onFulfilled, onRejected);
复制代码
[[Resolve]](promise, x)须要遵循如下规范异步
onFulfilled和onRejected方法应当是异步执行,且应该在then方法被调用的那一轮事件循环以后的微任务执行栈中执行。可使用宏任务macrotask和微任务microtask机制实现。也就是说宏任务完成后(Promise的then调用后),会清空微任务队列(执行onFulfilled或者onRejected)。函数
macrotask包含:script(总体代码)、setTimeout、setInterval、I/O、UI交互事件、postMessage 、requestAnimationFrame 、MessageChannel、etImmediate(Node.js 环境)源码分析
microtask包含:Promise.then、setImmediate、MutaionObserver、process.nextTick(Node.js 环境)post
下面👇是一个关于事件循环的例子🌰
Promise中的参数函数,应当是当即调用的。咱们这时先执行了resolve(1), 这会将外层的Promise的状态置为fulfilled态。可是这时外层的then尚未执行。
咱们接下来执行了Promise.resolve().then(() => console.log(2)), 咱们将then的onFulfilled,push到了macrotask队列中,会在宏任务执行完成后清空微任务。
执行外层Promise的then, onFulfilled, push到了macrotask队列中。
接着执行console.log(3), 而后清空macrotask队列,执行2,1(队列先进先出)
const pending = 0
const fulfilled = 1
const rejected = 2
function reject (promise, result) {}
function resolve (promise, reason) {}
export default class Promise {
constructor (fn) {
this.fn = fn
// Promise的状态, 初始状态为pending
this._state = pending
// Promise的fulfilled态的缘由,或者Promise的rejected态的理由
this._value = null
// 存储then的队列
this._tasks = []
// 建立Promise对象后,当即执行fn
this.init()
}
init () {
try {
// 执行fn, 传入包装后的resolve,reject
// reject,resolve会修改promise的状态
this.fn(
(result) => resolve(this, result),
(reason) => reject(this, reason)
)
} catch (error) {
reject(this)
}
}
}
复制代码
根据规范2.2.6: then may be called multiple times on the same promisethen能够在同一个promise中屡次调用。因此咱们用一个数组存储then的结果。
根据规范2.2.1: A promise’s then method accepts two arguments. Both onFulfilled and onRejected are optional arguments。then接受两个参数, 两个参数可选。
根据规范2.2.1.1, 2.2.1.2: If onFulfilled is not a function, it must be ignored. If onRejected is not a function, it must be ignored.。onFulfilled, onRejected必须是函数负责会被忽略。
根据规范2.2.2, 2.2.3, onFulfilled必须在状态为fulfilled调用, onRejected必须在状态为rejected调用
根据规范2.2.7: then must return a promise。then必须返回一个promise。
🤔️ 为何不能返回当前的promise?由于根据规范2.1.2, 2.1.3, promise被修改状态后,不能再次修改状态。咱们若是须要执行then的callback须要修改promise的状态。
咱们使用task封装📦then的回调以及then返回的promise。
class Task {
constructor (onFulfilled, onRejected, promise) {
if (typeof onFulfilled !== 'function') {
onFulfilled = null
}
if (typeof onRejected !== 'function') {
onRejected = null
}
this.onFulfilled = onFulfilled
this.onRejected = onRejected
this.promise = promise
}
}
class Promise {
// ...
then (onFulfilled, onRejected) {
let nextPromise = new Promise(function () {})
let task = new Task(onFulfilled, onRejected, nextPromise)
if (this._state === pending) {
this._tasks.push(task)
} else {
handlePromise(this, task)
}
// 返回新的promise
return nextPromise
}
}
复制代码
catch函数一样会返回新的promise, 可是在建立task时,咱们不会传入onFulfilled参数。因此当promise当为fulfilled态,虽然catch的回调一样存放_task中,可是因为callback为null, 在handlePromise中会向下穿透。
class Promise {
// ...
catch (onRejected) {
let nextPromise = new Promise(function () {})
// onFulfilled设置为null
let task = new Task(null, onRejected, nextPromise)
if (this._state === pending) {
this._tasks.push(task)
} else {
handlePromise(this, task)
}
// 返回新的promise
return nextPromise
}
}
复制代码
finally方法用于指定无论Promise对象最后状态如何,都会执行的操做。
咱们不管promise的状态如何,都在promise的最后面添加then,并传入了onFulfilled, onRejected两个回调。在回调中,咱们执行finally的callback参数。这样不管以前的promise是fulfilled态,仍是rejected态,都会执行finally添加的参数。
class Promise {
// ...
finally (callback) {
// this指向调用finally的对象
const self = this
// 向Promise链中添加then,不管,promise是resolve态仍是reject态,都会执行callback
// 而且会经过then,继续将result或reason向下传递
return self.then(
result => Promise.resolve(callback()).then(_ => result),
reason => Promise.resolve(callback()).then(_ => { throw reason })
)
}
}
复制代码
resolve用来修改promise状态,将promise状态设置为fulfilled态, 并执行then的onFulfilled回调
根据规范**2.3.1: If promise and x refer to the same object, reject promise with a TypeError as the reason.**若是promise与x相等,咱们使用TypeError的错误拒绝promise
根据规范2.3.2。若是result是promise,而且处于pending态,promise须要保持pending态,直到result被执行和拒绝后,咱们使用result的状态履行或者拒绝promise。若是result是promise,而且处于fulfilled或rejected态,咱们使用result的状态拒绝或者履行promise。
根据规范2.3.3, 咱们判断result是否为一个Object。若是result为Object, 咱们则取出它的then的属性, 判断then属性是否为Function, 若是then为Function, 咱们设置then的做用域的this指向result, 咱们传入resolvePromise, rejectPromise做为参数。
根据规范2.3.4: If x is not an object or function, fulfill promise with x, 若是x不是函数或者对象,咱们用result结果做为参数执行promise。
function resolve (promise, result) {
if (promise === result) {
throw reject(promise, new TypeError('promise and x refer to the same object'))
}
if (isPromise(result)) {
if (result._state === pending) {
result._tasks.concat(promise._tasks)
} else if (result._state === fulfilled || result._state === rejected) {
let task
while (task = promise._tasks.shift()) {
handlePromise(result, task)
}
}
return
}
if (isObject(result)) {
let then = null
try {
then = result.then
} catch (error) {
reject(promise, error)
}
if (isFunction(then)) {
try {
let resolvePromise = function (y) {
resolve(promise, y)
}
let rejectPromise = function (r) {
reject(promise, r)
}
then.call(result, resolvePromise, rejectPromise)
} catch (error) {
reject(promise, error)
}
return
}
}
promise._state = fulfilled
promise._value = result
if (promise._tasks && promise._tasks.length) {
let task = null
while (task = promise._tasks.shift()) {
handlePromise(promise, task)
}
}
}
复制代码
reject将promise的状态设置为rejected, 并以当前的promise的状态,执行promise中经过then注册的onRejected回调。
function reject (promise, reason) {
if (promise._state !== pending) {
return
}
promise._state = rejected
promise._value = reason
let task
while (task = promise._tasks.shift()) {
handlePromise(promise, task)
}
}
复制代码
handlePromise函数主要根据当前的promise的状态, 以及内容(resolve或者reject的参数)。处理经过then注册的回调。而且会链式的调用,注册在then返回的新promise的上的then的回调
// 将回调的结果,传入第二个then中
fn().then().then()
复制代码
根据规范2.2.4, 以及规范给出的注解。当promise的状态改变,onFulfilled, onRejected并不会当即执行,并且在本次的宏任务完成后,才会执行onFulfilled或者onRejected。而setImmediate则是将代码push到微任务队列中。在宏任务中会清空微任务队列。
function handlePromise (prevPromise, task) {
// 须要在宏任务完后的微任务队列中执行
setImmediate(() => {
// nextPromise是then返回的promise
const { onFulfilled, onRejected, promise: nextPromise } = task
let callback = null
let value = prevPromise._value
let state = prevPromise._state
if (state === fulfilled) {
callback = onFulfilled
} else if (state === rejected) {
callback = onRejected
}
if (!callback) {
// 若是在promise中没有注册callback
if (state === fulfilled) {
resolve(nextPromise, value)
} else if (state === rejected) {
reject(nextPromise, value)
}
} else {
try {
const result = callback(value)
// 对then中返回promise处理
// 将callback返回的结果,带入到新的promise中
resolve(nextPromise, result)
} catch (error) {
reject(nextPromise, error)
}
}
})
}
复制代码
Promise.resolve方法返回一个新的Promise对象,状态为resolved。Promise.reject(reason)方法也会返回一个新的 Promise实例,该实例的状态为rejected。
class Promise {
// ...
static resolve (result) {
return new Promise((resolve) => { resolve(result) })
}
static reject (reason) {
return new Promise((_, reject) => { reject(reason) })
}
}
复制代码
Promise.all和Promise.race必须接受一个数组为参数,数组中为多个Promise的实例。Promise.all和Promise.race的使用我就再也不这里赘述了。
Promise.all会使用计数器,记录Promise数组中的全部Promise实例的状态是否都变为fulfilled态,若是计数器的长度和数组长度一致,咱们则会将Promise.all的状态设置为fulfilled态。
class Promise {
static race (promises) {
if (isArray(promises)) {
let promisesLength = promises.length
return new Promise((resolve, reject) => {
for (let i = 0; i < promisesLength; i++) {
promises[i].then((result) => {
resolve(result)
}).catch((error) => {
reject(error)
})
}
})
} else {
throw new TypeError('The arguments must be arrays')
}
}
static all (promises) {
if (isArray(promises)) {
let promisesLength = promises.length
let counter = 0
let resultList = []
return new Promise((resolve, reject) => {
for (let i = 0; i < promisesLength; i++) {
promises[i].then((result) => {
counter += 1
resultList.push(result)
if (counter === promisesLength) {
resolve(resultList)
}
}).catch((error) => {
reject(error)
})
}
})
} else {
throw new TypeError('The arguments must be arrays')
}
}
}
复制代码