https://github.com/zhaoyiming0803/promise
Promise.js v1.0
https://github.com/zhaoyiming0803/promise
es6-javascript promise
Last synced: 9 months ago
JSON representation
Promise.js v1.0
- Host: GitHub
- URL: https://github.com/zhaoyiming0803/promise
- Owner: zhaoyiming0803
- License: mit
- Created: 2018-02-25T05:43:05.000Z (almost 8 years ago)
- Default Branch: dev
- Last Pushed: 2023-06-05T05:44:52.000Z (over 2 years ago)
- Last Synced: 2025-01-26T16:32:09.639Z (10 months ago)
- Topics: es6-javascript, promise
- Language: HTML
- Homepage:
- Size: 47.9 KB
- Stars: 12
- Watchers: 1
- Forks: 7
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Promise
注意:熟悉 Promise 基本用法之后再阅读此文会更好,可参考中文版《Promises/A+规范》:http://www.ituring.com.cn/article/66566 。
### 个人理解:
Promise 本身没有解决「异步回调地狱」的问题,async await 才解决了。
Promise 真正解决的是「信任问题」,把回调函数的执行权放到开发者手中,
比如 [demo](https://github.com/zhaoyiming0803/test-code/blob/master/test288.js) 所示:
就算第三方库 ajax 执行多次(resolve 或 reject),注册的 then 回调也只会执行一次。
Promise 本身不会回调过晚,只要决议了,它就会按照规定运行。至于服务器或者网络的问题,并不是 Promise 能解决的,一般这种情况会使用 Promise 的竞态 catch。
### 1、简易实例
``` javascript
var p = new Promise(function (resolve, reject) {
$.ajax({
type: 'POST',
url: 'https://example.com',
data: {
uname: 'zhaoyiming',
upwd: '123456'
},
dataType: 'json',
success: function (res) {
res.errorCode === 200 ? resolve(res) : reject(res);
},
error: function (res) {
reject(res);
}
});
});
p.then(function (value) {
console.log(value);
}, function (reason) {
console.log(reason);
});
```
从以上代码可以看出,Promise 是一个构造函数,实例化之后,可以通过它的 then 方法【注册】promise 异步操作成功时执行的回调,使得异步调用变得非常简单方便。
之所以说是注册,是因为它就是一种【发布订阅模式】。
### 2、试着实现一个 Promise 雏形
``` javascript
function Promise (fn) {
this._resolves = []
this._rejects = []
}
Promise.prototype.then = function (onFulfilled, onRejected) {
return new Promise((onFulfilledNext, onRejectedNext) => {
});
};
```
通过 then 方法,将执行成功或失败之后的回调函数放入队列里边(Promise 内部定义的 handles 对象,resolves 存放成功时的回调,rejects 存放失败时的回调)。
既然是发布订阅模式,那么首先得订阅,就像我们看到某些杂志的文章非常好,就可以订阅他们的邮箱,这样每天有新的文章更新时,我们的邮箱才能收到并提醒我们去阅读。
所以,resolve 和 reject 的执行必须是包含在一个异步方法内(ajax,setTimeout 等等),这个时候,会首先执行 then,最后异步执行完成之后再依次执行通过 then 注册的回调。
then 中 return Promise 实例,实现了链式调用。
### 3、Promise 内部加入延时机制
理论上,Promise 内都是做异步操作的,但是没法保证所有的人都这样做(心急写代码忘了呢^-^).
也就是在 then 方法注册回调之前,resolve 或 reject 函数就执行了。
这显然是不允许的,Promises/A+ 规范明确要求回调需要通过异步方式执行,用以保证一致可靠的执行顺序。
``` javascript
var p = new Promise(function (resolve, reject) {
// do something...
resolve(value);
});
p.then(function (res) {
console.log(res);
});
```
我们可以做一些处理,保证在 resolve 执行之前,then 方法已经注册完所有的回调:在 Promise 内部,将 resolve 或 reject 包裹在 setTimeout 内:
``` javascript
function Promise (fn) {
this._resolves = []
this._rejects = []
var _this = this;
fn(function (value) {
setTimeout(function () {
for (var i = 0, len = _this.handles.resolves.length; i < len; i += 1) {
_this.handles.resolves[i]();
}
}, 0);
}, function (reason) {
setTimeout(function () {
for (var i = 0, len = _this.handles.rejects.length; i < len; i += 1) {
_this.handles.rejects[i]();
}
}, 0);
});
}
```
但是,这样好像还存在一个问题,可以细想一下:如果 Promise 异步操作已经成功,这时,在异步操作成功之前注册的回调都会执行,但是在 Promise 异步操作成功这之后调用的 then 注册的回调就再也不会执行了,这肯定是不行的。
### 4、通过状态来决定回调什么时候执行
Promises/A+ 规范中的 2.1 Promise States 中明确规定了,pending可 以转化为 fulfilled 或 rejected 并且`只能转化一次`,也就是说如果 pending 转化到 fulfilled 状态,那么就不能再转化到rejected。并且 fulfilled 和 rejected 状态只能由 pending 转化而来,两者之间不能互相转换。如图所示:

``` javascript
function Promise (fn) {
this._resolves = []
this._rejects = []
this._status = 0; // 0: pending 1: resolve 2: reject
}
Promise.prototype.then = function (fulfilled, rejected) {
return new Promise((onFulfilledNext, onRejectedNext) => {
// ...
switch (this._status) {
case 0: // 如果是pedding状态,则将回调加入到队列
this._resolves.push(fulfilled)
this._rejects.push(rejected)
break
case 1: // 如果异步已经执行成功,则立刻执行then中注册的resolve方法
fulfilled(this._value)
break
case 2: // 如果异步已经执行失败,则立刻执行then中注册的reject方法
rejected(this._value)
break
}
})
};
```
### 5、总结
通过 Promise.prototype.then 方法将观察者方法注册到被观察者 Promise 对象中,同时返回一个新的 Promise 对象,以便可以链式调用。
被观察者管理内部 pending、fulfilled 和 rejected 的状态转变,同时通过构造函数中传递的 resolve 和 reject 方法以主动触发状态转变和通知观察者。
了解了 Promise 执行原理,再去扩展 then 之后的其他方法就很好做了。例如 Promise.all() Promise.rece() 等等。
这里 https://github.com/zhaoyiming0803/Promise/blob/master/src/Promise.js 实现了 Promise,可以作为参考。
### 个人微信&QQ:1047832475

### --- 分割线 ---
如果对您有帮助,您可以点右上角 "Star" 支持一下 谢谢! ^_^
或者您可以 "follow" 一下,我会不断开源更多的有趣的项目。