(对于完整的 Promise 实现,向下滚动)。
您的代码中的一些问题
有几个问题,但我认为您的代码中的主要错误是您将提供给then方法的参数作为参数传递给 promise 构造函数:
this.then=function(resolve,reject) {
    var nextPromise=new Aaa(resolve,true);
    // ...
尽管这两个参数都是回调函数,但它们具有不同的签名,并且用于完全不同的目的:
- 应许构造函数的参数是一个回调函数将被执行,立即,同步。一个函数作为第一个参数传递给它,您可以使用它来解析您正在创建的Promise。
 
- 该方法的(第一个)参数
then是一个回调函数,它只会在稍后异步执行,当基本Promise被解析时,解析的值作为参数传递给它。 
您也可以在代码中看到不同之处,其中将构造函数的参数存储为f属性。你有这两个:
t.thens[i].f(g);
...其中g是解析值,但也是这个:
this.f(this.resolve,this.reject); 
...其中参数是函数。当您创建nextPromise时,实际上您将首先使用这两个参数调用f,然后使用g参数调用。
从头开始的 Promises/A+ 兼容实现
我们可以按照Promises/A+ 规范中的要求构建我们自己的 Promise 实现:
2.1 Promise状态
只允许 2 种状态转换:从待处理到已完成,以及从待处理到拒绝。没有其他转换是可能的,并且一旦执行了转换,Promise值(或拒绝原因)不应改变。
这是一个简单的实现,将遵守上述限制。注释引用了上述规范中的编号要求:
function MyPromise(executor) {
    this.state = 'pending';
    this.value = undefined;
    executor(this.resolve.bind(this), this.reject.bind(this));
}
// 2.1.1.1: provide only two ways to transition
MyPromise.prototype.resolve = function (value) {
    if (this.state !== 'pending') return; // 2.1.2.1, 2.1.3.1: cannot transition anymore
    this.state = 'fulfilled'; // 2.1.1.1: can transition
    this.value = value; // 2.1.2.2: must have a value
}
MyPromise.prototype.reject = function (reason) {
    if (this.state !== 'pending') return; // 2.1.2.1, 2.1.3.1: cannot transition anymore
    this.state = 'rejected'; // 2.1.1.1: can transition
    this.value = reason; // 2.1.3.2: must have a reason
}
当然,这里并没有提供then方法,这是 Promises 的关键:
2.2then方法
这是规范的核心。可以扩展上面的代码以公开then方法,该方法返回一个promise并提供适当then回调的异步执行,仅一次,提供多次then调用,将异常转换为拒绝等。
所以下面的代码添加了then方法,还有一个broadcast单独定义的函数,因为它必须在任何状态改变时调用:这不仅包括then方法的效果(一个promise被添加到列表中),还包括的resolve和reject的方法(状态和值的变化)。
function MyPromise(executor) {
    this.state = 'pending';
    this.value = undefined;
    // A list of "clients" that need to be notified when a state
    //   change event occurs. These event-consumers are the promises
    //   that are returned by the calls to the `then` method.
    this.consumers = [];
    executor(this.resolve.bind(this), this.reject.bind(this));
}
// 2.1.1.1: provide only two ways to transition
MyPromise.prototype.resolve = function (value) {
    if (this.state !== 'pending') return; // 2.1.2.1, 2.1.3.1: cannot transition anymore
    this.state = 'fulfilled'; // 2.1.1.1: can transition
    this.value = value; // 2.1.2.2: must have a value
    this.broadcast();
}    
MyPromise.prototype.reject = function (reason) {
    if (this.state !== 'pending') return; // 2.1.2.1, 2.1.3.1: cannot transition anymore
    this.state = 'rejected'; // 2.1.1.1: can transition
    this.value = reason; // 2.1.3.2: must have a reason
    this.broadcast();
}    
// A promise’s then method accepts two arguments:
MyPromise.prototype.then = function(onFulfilled, onRejected) {
    var consumer = new MyPromise(function () {});
    // 2.2.1.1 ignore onFulfilled if not a function
    consumer.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
    // 2.2.1.2 ignore onRejected if not a function
    consumer.onRejected = typeof onRejected === 'function' ? onRejected : null;
    // 2.2.6.1, 2.2.6.2: .then() may be called multiple times on the same promise
    this.consumers.push(consumer);
    // It might be that the promise was already resolved... 
    this.broadcast();
    // 2.2.7: .then() must return a promise
    return consumer;
};
MyPromise.prototype.broadcast = function() {
    var promise = this;
    // 2.2.2.1, 2.2.2.2, 2.2.3.1, 2.2.3.2 called after promise is resolved
    if (this.state === 'pending') return;
    // 2.2.6.1, 2.2.6.2 all respective callbacks must execute
    var callbackName = this.state == 'fulfilled' ? 'onFulfilled' : 'onRejected';
    var resolver = this.state == 'fulfilled' ? 'resolve' : 'reject';
    // 2.2.4 onFulfilled/onRejected must be called asynchronously
    setTimeout(function() {
        // 2.2.6.1, 2.2.6.2 traverse in order, 2.2.2.3, 2.2.3.3 called only once
        promise.consumers.splice(0).forEach(function(consumer) {
            try {
                var callback = consumer[callbackName];
                // 2.2.1.1, 2.2.1.2 ignore callback if not a function, else
                // 2.2.5 call callback as plain function without context
                if (callback) {
                    // TODO: 2.2.7.1. For now we simply fulfill the promise:
                    consumer.resolve(callback(promise.value)); 
                } else {
                    // 2.2.7.3 resolve in same way as current promise
                    consumer[resolver](promise.value);
                }
            } catch (e) {
                // 2.2.7.2
                consumer.reject(e);
            };
        })
    });
};
这几乎涵盖了一切,除了在TODO:评论中,必须调用所谓的Promise Resolution Procedure:
2.3 Promise 解决程序
这是一个以不同方式处理 thenables(甚至Promise)值的过程:该过程不会按原样返回值,而是对该值执行then方法,并使用从该then回调接收到的值异步履行Promise。规范中没有提到它,但这不仅在then方法中执行很有趣,而且在使用这样的值解析主要Promise时也很有趣。
所以现有的resolve方法应该替换为这个“Promise Resolution Procedure”,它会调用原来的方法。最初的可以称为“fulfill”,表示它将始终将Promise解决为已完成:
function MyPromise(executor) {
    this.state = 'pending';
    this.value = undefined;
    // A list of "clients" that need to be notified when a state
    //   change event occurs. These event-consumers are the promises
    //   that are returned by the calls to the `then` method.
    this.consumers = [];
    executor(this.resolve.bind(this), this.reject.bind(this));
}
// 2.1.1.1: provide only two ways to transition
MyPromise.prototype.fulfill = function (value) {
    if (this.state !== 'pending') return; // 2.1.2.1, 2.1.3.1: cannot transition anymore
    this.state = 'fulfilled'; // 2.1.1.1: can transition
    this.value = value; // 2.1.2.2: must have a value
    this.broadcast();
}    
MyPromise.prototype.reject = function (reason) {
    if (this.state !== 'pending') return; // 2.1.2.1, 2.1.3.1: cannot transition anymore
    this.state = 'rejected'; // 2.1.1.1: can transition
    this.value = reason; // 2.1.3.2: must have a reason
    this.broadcast();
}    
// A promise’s then method accepts two arguments:
MyPromise.prototype.then = function(onFulfilled, onRejected) {
    var consumer = new MyPromise(function () {});
    // 2.2.1.1 ignore onFulfilled if not a function
    consumer.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
    // 2.2.1.2 ignore onRejected if not a function
    consumer.onRejected = typeof onRejected === 'function' ? onRejected : null;
    // 2.2.6.1, 2.2.6.2: .then() may be called multiple times on the same promise
    this.consumers.push(consumer);
    // It might be that the promise was already resolved... 
    this.broadcast();
    // 2.2.7: .then() must return a promise
    return consumer;
};
MyPromise.prototype.broadcast = function() {
    var promise = this;
    // 2.2.2.1, 2.2.2.2, 2.2.3.1, 2.2.3.2 called after promise is resolved
    if (this.state === 'pending') return;
    // 2.2.6.1, 2.2.6.2 all respective callbacks must execute
    var callbackName = this.state == 'fulfilled' ? 'onFulfilled' : 'onRejected';
    var resolver = this.state == 'fulfilled' ? 'resolve' : 'reject';
    // 2.2.4 onFulfilled/onRejected must be called asynchronously
    setTimeout(function() {
        // 2.2.6.1, 2.2.6.2 traverse in order, 2.2.2.3, 2.2.3.3 called only once
        promise.consumers.splice(0).forEach(function(consumer) {
            try {
                var callback = consumer[callbackName];
                // 2.2.1.1, 2.2.1.2 ignore callback if not a function, else
                // 2.2.5 call callback as plain function without context
                if (callback) {
                    // 2.2.7.1. execute the Promise Resolution Procedure:
                    consumer.resolve(callback(promise.value)); 
                } else {
                    // 2.2.7.3 resolve in same way as current promise
                    consumer[resolver](promise.value);
                }
            } catch (e) {
                // 2.2.7.2
                consumer.reject(e);
            };
        })
    });
};
// The Promise Resolution Procedure: will treat values that are thenables/promises
// and will eventually call either fulfill or reject/throw.
MyPromise.prototype.resolve = function(x) {
    var wasCalled, then;
    // 2.3.1
    if (this === x) {
        throw new TypeError('Circular reference: promise value is promise itself');
    }
    // 2.3.2
    if (x instanceof MyPromise) {
        // 2.3.2.1, 2.3.2.2, 2.3.2.3
        x.then(this.resolve.bind(this), this.reject.bind(this));
    } else if (x === Object(x)) { // 2.3.3
        try {
            // 2.3.3.1
            then = x.then;
            if (typeof then === 'function') {
                // 2.3.3.3
                then.call(x, function resolve(y) {
                    // 2.3.3.3.3 don't allow multiple calls
                    if (wasCalled) return;
                    wasCalled = true;
                    // 2.3.3.3.1 recurse
                    this.resolve(y);
                }.bind(this), function reject(reasonY) {
                    // 2.3.3.3.3 don't allow multiple calls
                    if (wasCalled) return;
                    wasCalled = true;
                    // 2.3.3.3.2
                    this.reject(reasonY);
                }.bind(this));
            } else {
                // 2.3.3.4
                this.fulfill(x);
            }
        } catch(e) {
            // 2.3.3.3.4.1 ignore if call was made
            if (wasCalled) return;
            // 2.3.3.2 or 2.3.3.3.4.2
            this.reject(e);
        }
    } else {
        // 2.3.4
        this.fulfill(x);
    }
}
这现在符合 Promises/A+ 标准,至少它通过了测试套件。然而,Promise 对象暴露了太多的方法和属性:
一个then只有一个 Promise 对象
上面构建的构造函数创建的东西更像是一个延迟对象,即暴露resolve和reject方法。更糟糕的是,status和value属性是可写的。因此,将 this 视为不安全的 Deferred 对象的构造函数并创建一个单独的 Promise 构造函数来构建它会更合乎逻辑,但仅公开所需的内容:then可以访问resolve和的方法和构造函数回调reject。
deferred 对象然后可以不用构造函数回调参数,并通过promise属性提供对纯 Promise 对象的访问:
function Deferred() {
    this.state = 'pending';
    this.value = undefined;
    this.consumers = [];
    this.promise = Object.create(MyPromise.prototype, {
        then: { value: this.then.bind(this) }
    });
}
// 2.1.1.1: provide only two ways to transition
Deferred.prototype.fulfill = function (value) {
    if (this.state !== 'pending') return; // 2.1.2.1, 2.1.3.1: cannot transition anymore
    this.state = 'fulfilled'; // 2.1.1.1: can transition
    this.value = value; // 2.1.2.2: must have a value
    this.broadcast();
}    
Deferred.prototype.reject = function (reason) {
    if (this.state !== 'pending') return; // 2.1.2.1, 2.1.3.1: cannot transition anymore
    this.state = 'rejected'; // 2.1.1.1: can transition
    this.value = reason; // 2.1.3.2: must have a reason
    this.broadcast();
}    
// A promise’s then method accepts two arguments:
Deferred.prototype.then = function(onFulfilled, onRejected) {
    var consumer = new Deferred();
    // 2.2.1.1 ignore onFulfilled if not a function
    consumer.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
    // 2.2.1.2 ignore onRejected if not a function
    consumer.onRejected = typeof onRejected === 'function' ? onRejected : null;
    // 2.2.6.1, 2.2.6.2: .then() may be called multiple times on the same promise
    this.consumers.push(consumer);
    // It might be that the promise was already resolved... 
    this.broadcast();
    // 2.2.7: .then() must return a promise
    return consumer.promise;
};
Deferred.prototype.broadcast = function() {
    var promise = this;
    // 2.2.2.1, 2.2.2.2, 2.2.3.1, 2.2.3.2 called after promise is resolved
    if (this.state === 'pending') return;
    // 2.2.6.1, 2.2.6.2 all respective callbacks must execute
    var callbackName = this.state == 'fulfilled' ? 'onFulfilled' : 'onRejected';
    var resolver = this.state == 'fulfilled' ? 'resolve' : 'reject';
    // 2.2.4 onFulfilled/onRejected must be called asynchronously
    setTimeout(function() {
        // 2.2.6.1, 2.2.6.2 traverse in order, 2.2.2.3, 2.2.3.3 called only once
        promise.consumers.splice(0).forEach(function(consumer) {
            try {
                var callback = consumer[callbackName];
                // 2.2.1.1, 2.2.1.2 ignore callback if not a function, else
                // 2.2.5 call callback as plain function without context
                if (callback) {
                    // 2.2.7.1. execute the Promise Resolution Procedure:
                    consumer.resolve(callback(promise.value)); 
                } else {
                    // 2.2.7.3 resolve in same way as current promise
                    consumer[resolver](promise.value);
                }
            } catch (e) {
                // 2.2.7.2
                consumer.reject(e);
            };
        })
    });
};
// The Promise Resolution Procedure: will treat values that are thenables/promises
// and will eventually call either fulfill or reject/throw.
Deferred.prototype.resolve = function(x) {
    var wasCalled, then;
    // 2.3.1
    if (this.promise === x) {
        throw new TypeError('Circular reference: promise value is promise itself');
    }
    // 2.3.2
    if (x instanceof MyPromise) {
        // 2.3.2.1, 2.3.2.2, 2.3.2.3
        x.then(this.resolve.bind(this), this.reject.bind(this));
    } else if (x === Object(x)) { // 2.3.3
        try {
            // 2.3.3.1
            then = x.then;
            if (typeof then === 'function') {
                // 2.3.3.3
                then.call(x, function resolve(y) {
                    // 2.3.3.3.3 don't allow multiple calls
                    if (wasCalled) return;
                    wasCalled = true;
                    // 2.3.3.3.1 recurse
                    this.resolve(y);
                }.bind(this), function reject(reasonY) {
                    // 2.3.3.3.3 don't allow multiple calls
                    if (wasCalled) return;
                    wasCalled = true;
                    // 2.3.3.3.2
                    this.reject(reasonY);
                }.bind(this));
            } else {
                // 2.3.3.4
                this.fulfill(x);
            }
        } catch(e) {
            // 2.3.3.3.4.1 ignore if call was made
            if (wasCalled) return;
            // 2.3.3.2 or 2.3.3.3.4.2
            this.reject(e);
        }
    } else {
        // 2.3.4
        this.fulfill(x);
    }
}
function MyPromise(executor) {
    // A Promise is just a wrapper around a Deferred, exposing only the `then`
    // method, while `resolve` and `reject` are available in the constructor callback
    var df = new Deferred();
    // Provide access to the `resolve` and `reject` methods via the callback
    executor(df.resolve.bind(df), df.reject.bind(df));
    return df.promise;
}
这段代码有几个可能的优化,例如使延迟方法成为私有函数,并将类似的代码合并到更短的代码块中,但就目前而言,它非常清楚地显示了每个需求的覆盖范围。
快乐编码。