-
Notifications
You must be signed in to change notification settings - Fork 456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Promise的源码实现(完美符合Promise/A+规范) #2
Comments
大佬真棒!学习的榜样! |
棒棒哒 |
顶礼膜拜,看多了都是泪😭 |
小姐姐棒棒的,今天看了你的这篇promise,自己试着写了一遍 |
1 similar comment
小姐姐棒棒的,今天看了你的这篇promise,自己试着写了一遍 |
看小姐姐的文章能找到好工作 |
good |
let x = new Promise((resolve, reject) => {
resolve(
new Promise((resolve, reject) => {
resolve(2);
})
);
}).then(res => {
console.log(res);
}); 我发现一个问题就是,这个在浏览器的Promise中,和这里实现的Promise是不一致的,想问下这是新规范吗 |
resolvePromise中self是多余的,好几次以为是自身对象,debug走一遍之后发现是window,再往下面看的时候发现并没有用到。 |
// 1) Promise 是一个类或者一个方法 // then有返回值 // catch的特点是 如果都没有错误处理 一层层找 没有找到错误处理 会找最近的catch catch也是then // promise中实现链式调用 返回一个新的promise const PENDING = 'pending'; 看下这个呢 |
ES6 在 Promise/A+ 规范基础上扩展了一些功能,例如:resolve 解析 promise 和 thenable 对象,根据一些测试用例做了补充和修改(node环境),感兴趣可以参考 https://github.com/lfpdev/promise |
非常棒的一篇文章 |
错的,.then执行应该在同一tick,但是你这不是同一tick |
浏览器是 native code microtask,这毕竟是模拟的,其实是macrotask。 |
好文 点赞 |
个人觉得有两个地方需要改正。 const resolve = data =>{
// 只能是当前Promise类的实例,其他Pormise类的实例则不可
if(data instanceof Promise){
return data.then(resolve, reject)
}
if(this.state === PENDING){
this.state = RESOLVED
this.value = data
this.onResolvedCbs.forEach(fn => fn())
}
} 第二个地方是 |
2.3.2 x如果是一个Promise,代码中怎么没体现出来? |
@YvetteLau 想确认下 关于Promise.resolve的实现是不是对于thenable对象处理缺少了try catch 如果这样的话 会不会有问题 |
finally 那边是不是可以直接这样写: Promise.prototype.finally = function (onFinally) {
return this.then(onFinally, onFinally)
} |
不行哈,比如你看这样的代码 Promise.resolve(2).finally().then((val) => {
console.log(val);
}) finally不会影响promise一个状态的传递,你这个代码如果onFinally有返回值,就会影响到后面then的回调 |
源码复制后报错 @YvetteLau |
好像对 'thenable' 的参数不适用? |
有个问题 |
promise 本身就是一种 thenable,下面统一处理了,效果一样的,只是没有按照规范那样实现 |
确实用不到,resolvePromise 是在全局中声明的函数,this 指向的是全局对象,除非传 promise 实例给 resolvePromise,否则它根本拿不到 promise 实例 |
``> ```js
确实,我也发现了这个问题,然后去网上找 Promise 实现,发现很多手写 Promise 实现都没有考虑给 resolve 函数传另一个 promise 对象的情况。
对于 es6 的 Promise,输出的是:p1; |
可以使用 window.queueMicroTask(callback) 来队列 microtask |
您好,我是黄丽,您的邮件我已收到,谢谢
|
我也发现了网上的实现都没处理这种这种情况, 只处理了 then 中返回 promise的情况, 如果在 new Promise的时候, 直接 resolve 了另一个 promise, 网上的实现都有问题, 但是能通过 promise a+ 测试 |
您好,我是黄丽,您的邮件我已收到,谢谢
|
Promise是前端面试中的高频问题,我作为面试官的时候,问Promise的概率超过90%,据我所知,大多数公司,都会问一些关于Promise的问题。如果你能根据PromiseA+的规范,写出符合规范的源码,那么我想,对于面试中的Promise相关的问题,都能够给出比较完美的答案。
我的建议是,对照规范多写几次实现,也许第一遍的时候,是改了多次,才能通过测试,那么需要反复的写,我已经将Promise的源码实现写了不下七遍。
Promise的源码实现
有专门的测试脚本可以测试所编写的代码是否符合PromiseA+的规范。
首先,在promise实现的代码中,增加以下代码:
安装测试脚本:
如果当前的promise源码的文件名为promise.js
那么在对应的目录执行以下命令:
promises-aplus-tests中共有872条测试用例。以上代码,可以完美通过所有用例。
对上面的代码实现做一点简要说明(其它一些内容注释中已经写得很清楚):
onFulfilled 和 onFulfilled的调用需要放在setTimeout,因为规范中表示: onFulfilled or onRejected must not be called until the execution context stack contains only platform code。使用setTimeout只是模拟异步,原生Promise并非是这样实现的。
在 resolvePromise 的函数中,为何需要usedd这个flag,同样是因为规范中明确表示: If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored. 因此我们需要这样的flag来确保只会执行一次。
self.onFulfilled 和 self.onRejected 中存储了成功的回调和失败的回调,根据规范2.6显示,当promise从pending态改变的时候,需要按照顺序去指定then对应的回调。
PromiseA+的规范(翻译版)
PS: 下面是我翻译的规范,供参考
2.1 Promise States
Promise 必须处于以下三个状态之一: pending, fulfilled 或者是 rejected
2.1.1 如果promise在pending状态
2.1.2 如果promise在fulfilled状态
2.1.3 如果promise在rejected状态
概括即是:promise的状态只能从pending变成fulfilled,或者从pending变成rejected.promise成功,有成功的value.promise失败的话,有失败的原因
2.2 then方法
promise必须提供一个then方法,来访问最终的结果
promise的then方法接收两个参数
2.2.1 onFulfilled 和 onRejected 都是可选参数
2.2.2 如果 onFulfilled 是函数:
2.2.3 如果 onRejected 是函数:
2.2.4 onFulfilled 和 onRejected 应该是微任务
2.2.5 onFulfilled 和 onRejected 必须作为函数被调用
2.2.6 then方法可能被多次调用
2.2.7 then必须返回一个promise
2.3 resolvePromise
resolvePromise(promise2, x, resolve, reject)
2.3.1 如果 promise2 和 x 相等,那么 reject promise with a TypeError
2.3.2 如果 x 是一个 promsie
2.3.3 如果 x 是一个 object 或者 是一个 function
2.3.4 如果 x 不是一个 object 或者 function,fulfill promise with x.
Promise的其他方法
虽然上述的promise源码已经符合PromiseA+的规范,但是原生的Promise还提供了一些其他方法,如:
下面具体说一下每个方法的实现:
Promise.resolve(value) 返回一个以给定值解析后的Promise 对象.
thenable对象的执行加 setTimeout的原因是根据原生Promise对象执行的结果推断的,如下的测试代码,原生的执行结果为: 20 400 30;为了同样的执行顺序,增加了setTimeout延时。
测试代码:
Promise.reject方法和Promise.resolve不同,Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。
Promise.prototype.catch 用于指定出错时的回调,是特殊的then方法,catch之后,可以继续 .then
不管成功还是失败,都会走到finally中,并且finally之后,还可以继续then。并且会将值原封不动的传递给后面的then.
Promise.all(promises) 返回一个promise对象
测试代码:
Promise.race函数返回一个 Promise,它将与第一个传递的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。
如果传的参数数组是空,则返回的 promise 将永远等待。
如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race 将解析为迭代中找到的第一个值。
测试代码:
The text was updated successfully, but these errors were encountered: