阅读指南
- 实际代码约120行
- 先看
done
,fulfill
,reject
实现,非常简单 - 再看
then
,和文档里描述的resolve
过程 - 中文版规范 http://segmentfault.com/a/1190000002452115
- 几乎没有其它任何功能, 仅仅是理解和学习
- github https://github.com/William17/taxi
(function() {
'use strict';
// 用于异步执行 onFulfilled/onRejected
// `setImmediate` or `function(fn) { setTimeout(fn, 0) }` in browser
// `process.nextTick` in node
var asyncCall = process.nextTick;
// 2.3
// Promise解析过程 是以一个promise和一个值做为参数的抽象过程,
// 可表示为
// [[Resolve]](promise, x)
function resolve(promise, x) {
// 2.3.1
// 如果promise 和 x 指向相同的值,
// 使用 TypeError做为原因将promise拒绝
if (promise === x) {
return promise.reject(new TypeError('The promise and its value refer to the same object'));
}
// 2.3.3
// 如果x是一个对象或一个函数
if (x && (typeof x === 'function' || typeof x === 'object')) {
// 2.3.3.3
// 如果 resolvePromise 和 rejectPromise 都被调用了,
// 或者被调用了多次,则只第一次有效,后面的忽略
// // 我们用 called 作为标识防止被多次调用
var called = false,
then;
try {
// 2.3.3.1
// 将 then 赋为 x.then
then = x.then;
if (typeof then === 'function') {
// 2.3.3.3
// 如果 then 是一个函数,
// 以x为this调用then函数,
// 且第一个参数是resolvePromise,
// 第二个参数是rejectPromise
then.call(x, function(y) {
// 2.3.3.3.1
// 当 resolvePromise 被以 y为参数调用,
// 执行 [[Resolve]](promise, y)
if (!called) {
called = true;
resolve(promise, y);
}
}, function(r) {
// 2.3.3.3.2
// 当 rejectPromise 被以 r 为参数调用,
// 则以r为原因将promise拒绝。
if (!called) {
called = true;
promise.reject(r);
}
});
}else {
// 2.3.3.4
// 如果 then不是一个函数,则 以x为值fulfill promise
promise.fulfill(x);
}
}catch (e) {
// 2.3.3.2
// 如果在取x.then值时抛出了异常,
// 则以这个异常做为原因将promise拒绝
if (!called) {
called = true;
promise.reject(e);
}
}
}else {
// 2.3.4
// 如果 x 不是对象也不是函数,
// 则以x为值 fulfill promise
promise.fulfill(x);
}
}
function Taxi() {
// 0 pending, 1 fulfilled, 2 rejected
var _state = 0,
_value,
_onFulfills = [],
_onRejects = [];
this.done = function(onFulfilled, onRejected) {
if (_state === 0) {
// 如果还在pending,先把处理函数存起来
_onFulfills.push(onFulfilled);
_onRejects.push(onRejected);
}else {
// 否则,异步执行
asyncCall(function() {
if (_state === 1) {
if (typeof onFulfilled === 'function') {
onFulfilled(_value);
}
}else if (typeof onRejected === 'function') {
onRejected(_value);
}
});
}
};
/**
* 用于this.fulfill和this.reject内部调用的函数
* @param {number} state 0->pending, 1->fulfill, 2->reject
* @param {dynamic} value result 或 reason
*/
function _complete(state, value){
// 只能 fulfill或reject一次, 后面的忽略
if (!_state) {
_state = state;
_value = value;
// 根据 state 获取需要处理的函数数组
// 异步执行
asyncCall(function() {
var handlers = state == 1 ? _onFulfills : _onRejects;
handlers.forEach(function(fn) {
if (typeof fn === 'function') {
fn(value);
}
});
// 执行完之后,解除数组引用
_onFulfills = null;
_onRejects = null;
});
}
}
this.fulfill = function(value) {
_complete(1, value);
};
this.reject = function(value) {
_complete(2, value);
};
}
Taxi.prototype = {
constructor: Taxi,
catch: function(onRejected) {
this.then(null, onRejected);
},
then: function(onFulfilled, onRejected) {
// 2.2.7
// then 必须返回一个promise
// 所以我们new一个,等下用于返回
var taxi = new Taxi();
// this指向当前promise
// 2.2.2
// 如果onFulfilled是一个函数:
// 它必须在promise fulfilled后调用, 且promise的value为其第一个参数。
// 2.2.3
// 如果onRejected是一个函数,
// 它必须在promise rejected后调用, 且promise的reason为其第一个参数。
this.done(function(x) {
if (typeof onFulfilled === 'function') {
try {
// 2.2.7.1
// 如果onFulfilled 或 onRejected 返回了值x,
// 则执行Promise 解析流程[[Resolve]](promise2, x).
resolve(taxi, onFulfilled(x));
}catch (e) {
// 2.2.7.2
// 如果onFulfilled 或 onRejected抛出了异常e,
// 则promise2应当以e为reason被拒绝
taxi.reject(e);
}
}else {
// 2.2.7.3
// 如果 onFulfilled 不是一个函数且promise1已经fulfilled,
// 则promise2必须以promise1的值fulfilled.
taxi.fulfill(x);
}
}, function(x) {
if (typeof onRejected === 'function') {
try {
// 2.2.7.1
// 如果onFulfilled 或 onRejected 返回了值x,
// 则执行Promise 解析流程[[Resolve]](promise2, x).
resolve(taxi, onRejected(x));
}catch (e) {
// 2.2.7.2
// 如果onFulfilled 或 onRejected抛出了异常e,
// 则promise2应当以e为reason被拒绝
taxi.reject(e);
}
}else {
// 2.2.7.4
// 如果 OnReject 不是一个函数且promise1已经rejected,
// 则promise2必须以相同的reason被拒绝.
taxi.reject(x);
}
});
return taxi;
}
};
module.exports = Taxi;
}());
精神可嘉,精华
@i5ting 谢谢~:P
mark.谢谢
good
good
真棒~ Awesome Promise 上有Lie等简单实现, 如果不先看 specifications 的话, 实现看起来还真是一头雾水~
mark
@William17 每次 都 var taxi = new Taxi(); 。 这样的话 _onFulfills = [], _onRejects = []; 里面不都是一个函数吗,用数组干嘛? 为什么每次都要new ?
@wdragon1983 这些是规范规定的.
then
必须返回一个Promise
对象, 这样的话就可以像下面那样链式操作, 另外,这个对象当然应该是一个新的对象
p.then(fn1).then(fn2);
- 上面那种操作第二个then是新的
Promise
对象的. 如果要使用一开始的对象的then, 那就直接调用, 下面这种情况就可能出现多个fulfill或reject回调
p.then(fn1);
p.then(fn2);
p.then(fn3);
p.reject(fn4);
举一个例子, 如果你有几个模块都需要另外一个东西(例如websocket连接?), 像下面, 这样你可以把模块的代码分开, 更好维护
// 模块1
socketConnect.then(init);
// 模块2
socketConnect.then(init);
@William17 那意思就是 如果p.then(fn1).then(fn2); 这种调用方式 。_onFulfills = [], _onRejects = []; 其实就是一个 值得数组。 p.then(fn1); p.then(fn2); p.then(fn3); p.reject(fn4); 这种调用才会出现多个值得数组。
不过还是看的云里雾里,resolve方法里面不知道在干嘛。
@wdragon1983 确实是那样
resolve
方法, 大概可以这么理解, 就是当一个promise被一个值resolve的时候, 假设这个值是x
, 因为x
有可能是任何东西, 函数, 对象, 简单的原始值等等都有可能, 你可以看到resolve
里很多if
, 就是分情况处理, 你把各种情况理清楚了, 就明白了
mark