Promise
指标
- Promise A+标准
- 手写Promise
- 题目练习
Promise A+标准
术语
- promise: 一个领有合乎这个标准的行为的then办法的对象或函数。
- thenable: 定义了一个then办法的对象或函数。
- value: 任意非法的JavaScript值(包含undefined,thenable,promise)。
- exception: 应用throw语句抛出的一个值
- reason: 示意promise为什么被回绝的一个值
必要条件
Promise 状态
promise必须是这三个状态中的一种:期待态pending,解决态fulfilled或回绝态rejected
- 当promise处于
pending
状态的时候:
可能变为fulfilled
或者rejected
状态。 - 当promise处于
fulfilled
状态的时候:
2.1 肯定不能转换为任何其它状态
2.2 必须有一个不能扭转的value
- 当promise处于
rejected
状态的时候:
3.1 肯定不能转换为任何其它状态
3.2 必须有一个不能扭转的reason
在这里,"肯定不能扭转"意味着不变的身份(例如 ===),然而并不意味着深度不可变性。(译注者:这里应该是说只有值的援用雷同即可,并不需要援用中的每一个值都相等)
then办法
Promise
必须提供一个then
办法来拜访以后或最终的value
或reason
。
Promise的then办法承受俩个参数:
promise.then(onFulfilled, onRejected)
onFulfilled
和onRejected
都是可选的参数
1.1. 如果onFulfilled
不是一个函数,它必须被疏忽
1.2. 如果onRejected
不是一个函数,它必须被疏忽- 如果
onFulfilled
是一个函数
2.1. 在promise变成fulfilled
时,应该调用 onFulfilled, 参数是value
2.2. 在promise变成fulfilled
之前, 不应该被调用.
2.3. 它肯定不能被调用屡次。 - 如果
onRejected
是一个函数
2.1. 在promise变成rejected
时,应该调用 onRejected, 参数是reason
2.2. 在promise变成rejected
之前, 不应该被调用.
2.3. 它肯定不能被调用屡次。 - 在执行上下文栈中只蕴含平台代码之前,onFulfilled或onRejected肯定不能被调用
- 同一个promise上的then可能被调用屡次
6.1. 如果promise被解决,所有相应的onFulfilled回调必须依照他们原始调用then的程序执行
6.2. 如果promise被回绝,所有相应的onRejected回调必须依照他们原始调用then的程序执行 - then必须返回一个promise对象
promise2 = promise1.then(onFulfilled,onRejected)
resolvePromise
resolvePromise(promise2, x, resolve, reject)
- 如果promise和x援用同一个对象,用一个TypeError作为起因来回绝promise
- 如果x是一个promise,依据
x
的状态:
2.1. 如果x是pending
,promise必须放弃期待状态,直到x被解决或回绝
2.2. 如果x是fulfilled
,用雷同的value
解决promise
2.3. 如果x是rejected
,用雷同的reason
回绝promise 否则,如果x是一个对象或函数
3.1.让then成为x.then
let then = x.then.
3.2. 如果检索属性x.then导致抛出了一个异样e,用e作为起因回绝promise
3.3. 如果then是一个函数,用x作为this调用它。then办法的参数为俩个回调函数,第一个参数叫做resolvePromise,第二个参数叫做rejectPromise:3.3.1. 如果resolvePromise用一个值y调用,运行[[Resolve]](promise, y)。译者注:这里再次调用[[Resolve]](promise,y),因为y可能还是promise 3.3.2. 如果rejectPromise用一个起因r调用,用r回绝promise。译者注:这里如果r为promise的话,依旧会间接reject,回绝的起因就是promise。并不会等到promise被解决或回绝 3.3.3. 如果`resolvePromise`和`rejectPromise`都被调用,或者对同一个参数进行屡次调用,那么第一次调用优先,当前的调用都会被疏忽。译者注:这里次要针对thenable,promise的状态一旦更改就不会再扭转。 3.3.4. 如果调用then抛出了一个异样e, 3.3.4.1 如果`resolvePromise`或`rejectPromise`曾经被调用,疏忽它 3.3.4.2 否则,用`e`作为起因回绝promise
3.4. 如果then不是一个函数,用x解决promise
手写Promise
const PENDING = "pending";const FULFILLED = "fulfilled";const REJECTED = "rejected";/** * 1. 构建Promsie类 * 2. 定义3种状态类型 * 3. 设置初始状态 * 4. resolve和reject办法 * 5. 定义结构参数 * 5.1 入参是一个函数, 函数接管resolve和reject两个参数. * 5.2 留神在初始化promise的时候, 就要执行这个函数, 并且有任何报错都要通过reject抛出去 * 6. 实现then办法 */class MPromise { FULFILLED_CALLBACK_LIST = []; REJECTED_CALLBACK_LIST = []; _status = PENDING; constructor(fn) { // this.status = PENDING; this.value = null; this.reason = null; try { fn(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { this.reject(e.message); } } get status() { return this._status; } set status(newStatus) { this._status = newStatus; switch (newStatus) { case FULFILLED: { this.FULFILLED_CALLBACK_LIST.forEach((callback) => { callback(this.value); }); break; } case REJECTED: { this.REJECTED_CALLBACK_LIST.forEach((callback) => { callback(this.reason); }); break; } } } resolve(value) { if (this.status === PENDING) { this.value = value; this.status = FULFILLED; } } reject(reason) { if (this.status === PENDING) { this.reason = reason; this.status = REJECTED; } } then(onFulfilled, onRejected) { const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => value; const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => { throw reason; }; const promise2 = new MPromise((resolve, reject) => { const fulfilledMicrotask = () => { queueMicrotask(() => { try { const x = realOnFulfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); }; const rejectedMicrotask = () => { queueMicrotask(() => { try { const x = realOnRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); }; switch (this.status) { case FULFILLED: { fulfilledMicrotask(); break; } case REJECTED: { rejectedMicrotask(); break; } case PENDING: { this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask); this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask); } } }); return promise2; } resolvePromise(promise2, x, resolve, reject) { // 如果 newPromise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 newPromise if (promise2 === x) { return reject( new TypeError("The promise and the return value are the same") ); } if (x instanceof MPromise) { // 如果 x 为 Promise ,则使 newPromise 承受 x 的状态 // 也就是继续执行x,如果执行的时候拿到一个y,还要持续解析y queueMicrotask(() => { x.then((y) => { this.resolvePromise(promise2, y, resolve, reject); }, reject); }); } else if (typeof x === "object" || this.isFunction(x)) { // 如果 x 为对象或者函数 if (x === null) { // null也会被判断为对象 return resolve(x); } let then = null; try { // 把 x.then 赋值给 then then = x.then; } catch (error) { // 如果取 x.then 的值时抛出谬误 e ,则以 e 为据因回绝 promise return reject(error); } // 如果then是函数 if (this.isFunction(then)) { let called = false; try { then.call( x, // 如果 resolvePromise 以值 y 为参数被调用,则运行 resolvePromise (y) => { // 须要有一个变量called来保障只调用一次. if (called) return; called = true; this.resolvePromise(promise2, y, resolve, reject); }, // 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 回绝 promise (r) => { if (called) return; called = true; reject(r); } ); } catch (error) { // 如果调用 then 办法抛出了异样 e: if (called) return; // 否则以 e 为据因回绝 promise reject(error); } } else { resolve(x); } } else { resolve(x); } } static resolve(value) { if (value instanceof MPromise) { return value; } return new MPromise((resolve) => { resolve(value); }); } static reject(reason) { return new MPromise((resolve, reject) => { reject(reason); }); } static race(promiseList) { return new MPromise((resolve, reject) => { const length = promiseList.length; if (length === 0) { return resolve(); } else { for (let i = 0; i < length; i++) { MPromise.resolve(promiseList[i]).then( (value) => { return resolve(value); }, (reason) => { return reject(reason); } ); } } }); } static all(promiseList) { let results = []; let promiseCount = 0; let promisesLength = promiseList.length; return new MPromise((resolve) => { Promise.resolve(val).then( (res) => { promiseCount++; results[i] = res; if (promiseCount === promisesLength) { return resolve(results); } }, (err) => { return reject(err); } ); }); } isFunction(param) { return typeof param === "function"; }}
练习
- 求运行后果
const promise = new Promise((resolve, reject) => { console.log(1) resolve() console.log(2) // 这里有纳闷})promise.then(() => { console.log(3)})console.log(4)
运行后果:
1243
- 求运行后果
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000)})const promise2 = promise1.then(() => { throw new Error('error!!!') // 这里不太确定 status}) console.log('promise1', promise1)console.log('promise2', promise2) setTimeout(() => { console.log('promise1', promise1) console.log('promise2', promise2)}, 2000)
运行后果
promise1 Promise { <pending> }promise2 Promise { <pending> }(node:50928) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: error!!!(node:50928) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.promise1 Promise { 'success' }promise2 Promise { <rejected> Error: error!!! at promise.then (...) at <anonymous> }
- 求运行后果
const promise = new Promise((resolve, reject) => { resolve('success1') reject('error') resolve('success2')}) promise .then((res) => { console.log('then: ', res) }) .catch((err) => { console.log('catch: ', err) })
运行后果
then: success1
- 求运行后果
Promise.resolve(1) .then((res) => { console.log(res) return 2 }) .catch((err) => { return 3 }) .then((res) => { console.log(res) })
运行后果
12
catch如果胜利执行,会返回雷同的value也就是2.
- 求运行后果
const promise = new Promise((resolve, reject) => { setTimeout(() => { console.log('once') resolve('success') }, 1000)}) const start = Date.now()promise.then((res) => { console.log(res, Date.now() - start)})promise.then((res) => { console.log(res, Date.now() - start)})
运行后果
oncesuccess 1009success 1009
- 求运行后果
Promise.resolve() .then(() => { return new Error('error!!!') }) .then((res) => { console.log('then: ', res) }) .catch((err) => { console.log('catch: ', err) })
运行后果
then: Error: error!!! at Promise.resolve.then (...) at ...
then的onFulfilled函数外面批改rejected的:
return Promise.reject(new Error('error!!!'))throw new Error('error!!!')
- 求运行后果
const promise = Promise.resolve() .then(() => { return promise })promise.catch(console.error)
运行后果
TypeError: Chaining cycle detected for promise #<Promise> at <anonymous> at process._tickCallback (internal/process/next_tick.js:188:7) at Function.Module.runMain (module.js:667:11) at startup (bootstrap_node.js:187:16) at bootstrap_node.js:607:3
- 求运行后果
Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .then(console.log)
运行后果
1
解释:then函数的onFulfilled不为函数,默认为(value)=>value
- 求运行后果
Promise.resolve() .then(function success (res) { throw new Error('error') }, function fail1 (e) { console.error('fail1: ', e) }) .catch(function fail2 (e) { console.error('fail2: ', e) })
运行后果
fail2: Error: error at success (...) at ...
解释: resolve
函数执行完返回fullfile
状态的promsie对象。在第一个then
函数的onFullfield
抛出异样。则返回promsie对象的状态为rejected
。被catch
函数捕捉。
- 求运行后果
process.nextTick(() => { console.log('nextTick')})Promise.resolve() .then(() => { console.log('then') })setImmediate(() => { console.log('setImmediate')})console.log('end')
endnextTickthensetImmediate
解释: process.nextTick
和 promise.then
都属于 microtask,而 setImmediate
属于 macrotask,在事件循环的 check 阶段执行。事件循环的每个阶段(macrotask)之间都会执行 microtask,事件循环的开始会先执行一次 microtask。
小结
promise的实现最难了解的就是resolvePromise
,十分的绕。另外学习到的了一个新的APIqueueMicrotask
,有些文章是应用setTimeout
来模仿实现微工作调用。
setTimeout(() => {},0)
参考文章
- Promises/A+
- Promise/A+ 标准(译)
- Promise.all手动实现