基本的Javascript承诺实施尝试

为了更好地理解Javascript中承诺的工作方式,我决定试一试,并自己编写基本实现。

基本上我想实现承担对象(我称之为代码中的Aaa),它将函数作为参数。 这个函数可以调用resolve来resolve promise,或者拒绝reject它。 基本的实现和用法如下。 不知道第二个参数是否可以按照诺言规格接受,但这就是我迄今为止所获得的结果。

Aaa=function(f,pause) { 

    console.log("ggg");

    var t=this;
    this.f=f;
    this.thens=[];

    this.resolve=function(g) {

        for(var i=0;i<t.thens.length;i++)
        {
            // try/catch to be used later for dealing with exceptions

            try
            {
                t.thens[i].f(g);
                t.thens[i].resolve();
            }   
            catch(ex)
            {}

        }
    };  

    // to be implemented later
    this.reject=function(g) {};

    this.then=function(resolve,reject) {

        // i'm passing true for pause argument as we dont need to execute promise code just yet
        var nextPromise=new Aaa(resolve,true);

        this.thens.push(nextPromise);

        return nextPromise;
    }


    if(!pause)
        this.f(this.resolve,this.reject); 

}


var aaa=new Aaa(function(resolve,reject) {

    console.log("aaa");

    setTimeout(function() {

        console.log("fff");
        resolve("good");

    },2000);

    console.log("bbb");

});

所以现在可以创建,调用和解决承诺。 每then方法将返回新的AAA(无极),因此可以将这些链接。 现在,下面的代码使用上面创建的承诺和链条then回调。 then每个都会返回新的承诺,在这种情况下,它似乎工作得很好:

aaa.then(function(res) {

    console.log("ccc");
    console.log(res);

})
.then(function(res) {
    console.log("ddd");
    console.log(res);
},function(rej) {
    console.log("eee");
    console.log(rej);
});

我得到的输出是:

ggg
aaa 
bbb 
ggg 
ggg 
fff 
ccc 
good 
ddd 
undefined 

但问题是,当的一个then调用返回一个承诺:

aaa.then(function(res) {

    console.log("ccc");
    console.log(res);

    // here we return the promise manually. then next then call where "ddd" is output should not be called UNTIL this promise is resolved. How to do that?

        return new Aaa(function(resolve,reject) {

        console.log("iii");

        setTimeout(function() {
        console.log("kkk");
            resolve("good2");
            // reject("bad");

        },2000);

        console.log("jjj");

    }).then(function (res) {
        console.log("lll");

        console.log(res);
    });

})
.then(function(res) {
    console.log("ddd");
    console.log(res);
},function(rej) {
    console.log("eee");
    console.log(rej);
});

输出是:

ggg 
aaa 
bbb 
ggg 
ggg  
fff  
ccc  
good  
ggg  
iii  
jjj  
ggg  
ddd  
undefined  
kkk  
lll  
good2 

然后,输出ddd的调用不应被调用,直到我们刚添加的返回的promise被解析。

如何最好地实施?


有几种情况你不在这里处理。 最好的选择就是从承诺作为一个状态机开始:

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {

  // store state which can be PENDING, FULFILLED or REJECTED
  var state = PENDING;

  // store value once FULFILLED or REJECTED
  var value = null;

  // store sucess & failure handlers
  var handlers = [];
}

现在让我们定义一个简单的助手来使用我们的其余实现:

// a function that returns `then` if `value` is a promise, otherwise `null`
function getThen(value) {
  if (result && (typeof result === 'object' || typeof result === 'function')) {
    var then = value.then;
    if (typeof then === 'function') {
      return then;
    }
  }
  return null;
}

接下来,我们需要考虑可能发生的每个转换:

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {

  // store state which can be PENDING, FULFILLED or REJECTED
  var state = PENDING;

  // store value once FULFILLED or REJECTED
  var value = null;

  // store sucess & failure handlers
  var handlers = [];

  function resolve(result) {
    try {
      var then = getThen(result);
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      state = FULFILLED;
      value = result;
    } catch (e) {
      reject(e);
    }
  }

  function reject(error) {
    state = REJECTED;
    value = error;
  }
}

注意resolve如何能够接受一个承诺作为它的论据,但是一个承诺永远不会被另一个承诺所履行。 所以我们必须处理这个特殊情况。

还要注意,一个承诺只能完成/拒绝一次。 我们还有一个问题,即第三方Promise可能会行事不端,我们应该防范我们的代码。 出于这个原因,我不只是在resolve调用result.then(resolve, reject) 。 相反,我将它分解为一个单独的函数:

/**
 * Take a potentially misbehaving resolver function and make sure
 * onFulfilled and onRejected are only called once.
 *
 * Makes no guarantees about asynchrony.
 */
function doResolve(fn, onFulfilled, onRejected) {
  var done = false;
  try {
    fn(function (value) {
      if (done) return
      done = true
      onFulfilled(value)
    }, function (reason) {
      if (done) return
      done = true
      onRejected(reason)
    })
  } catch (ex) {
    if (done) return
    done = true
    onRejected(ex)
  }
}

所以现在我们有一个完整的状态机,但没有办法观察或触发状态的变化。 让我们开始添加一种方法来通过传入解析器函数来触发状态更改。

function Promise(fn) {
  if (typeof this !== 'object')
    throw new TypeError('Promises must be constructed via new');
  if (typeof fn !== 'function')
    throw new TypeError('fn must be a function');

  // store state which can be PENDING, FULFILLED or REJECTED
  var state = PENDING;

  // store value once FULFILLED or REJECTED
  var value = null;

  // store sucess & failure handlers
  var handlers = [];

  function resolve(result) {
    try {
      var then = getThen(result);
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      state = FULFILLED;
      value = result;
    } catch (e) {
      reject(e);
    }
  }

  function reject(error) {
    state = REJECTED;
    value = error;
  }

  doResolve(fn, resolve, reject);
}

正如您所看到的,我们重新使用doResolve是因为我们有另一个doResolve信任的解析器。 fn可能会多次调用resolvereject ,并且可能会引发错误。 我们需要处理所有这些情况(这就是doResolve所做的)。

我们现在有完成的状态机,但我们没有公开关于它处于什么状态的任何信息。让我们尝试添加一个.done(onFulfilled, onRejected)方法,就像.done(onFulfilled, onRejected)一样.then除了它不返回Promise和不处理由onFulfilledonRejected引发的错误。

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(fn) {
  if (typeof this !== 'object')
    throw new TypeError('Promises must be constructed via new');
  if (typeof fn !== 'function')
    throw new TypeError('fn must be a function');

  // store state which can be PENDING, FULFILLED or REJECTED
  var state = PENDING;

  // store value once FULFILLED or REJECTED
  var value = null;

  // store sucess & failure handlers
  var handlers = [];

  function resolve(result) {
    try {
      var then = getThen(result);
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      state = FULFILLED;
      value = result;
      handlers.forEach(handle);
      handlers = null;
    } catch (e) {
      reject(e);
    }
  }

  function reject(error) {
    state = REJECTED;
    value = error;
    handlers.forEach(handle);
    handlers = null;
  }

  function handle(handler) {
    if (state === PENDING) {
      handlers.push(handler);
    } else {
      if (state === FULFILLED && typeof handler.onFulfilled === 'function') {
        handler.onFulfilled(value);
      }
      if (state === REJECTED && typeof handler.onRejected === 'function') {
        handler.onRejected(value);
      }
    }
  }
  this.done = function (onFulfilled, onRejected) {
    setTimeout(function () { // ensure we are always asynchronous
      handle({
        onFulfilled: onFulfilled,
        onRejected: onRejected
      });
    }, 0);
  }

  doResolve(fn, resolve, reject);
}

请注意,我们必须如何处理在承诺完成/拒绝之前和之后调用.done的情况。

我们几乎有一个完整的承诺实现,但是,正如您在构建自己的实现时已经注意到的那样,我们需要一个返回Promise的.then方法。

我们可以从.done构建这个easilly:

this.then = function (onFulfilled, onRejected) {
  var self = this;
  return new Promise(function (resolve, reject) {
    return self.done(function (result) {
      if (typeof onFulfilled === 'function') {
        try {
          return resolve(onFulfilled(result));
        } catch (ex) {
          return reject(ex);
        }
      } else {
        return resolve(result);
      }
    }, function (error) {
      if (typeof onRejected === 'function') {
        try {
          return resolve(onRejected(error));
        } catch (ex) {
          return reject(ex);
        }
      } else {
        return reject(error);
      }
    });
  });
}

请注意,我们如何获得您现在挣扎着的东西,因为resolve接受Promise并等待解决问题。

NB我没有测试过这个Promise实现(尽管我所知道的最好是正确的)。 您应该测试您针对Promises / A +测试套件(https://github.com/promises-aplus/promises-tests)构建的任何实现,并且还可以找到Promises / A +规范(https://github.com/promises -aplus / promises-spec)可用于确定算法的任何特定部分的正确行为。 作为最终的资源,承诺是Promise规范的最小实现。


(对于完整的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参数调用f。

    从头开始遵守承诺/ A +标准

    我们可以通过遵循Promises / A +规范中的要求来构建自己的Promise实现:

    2.1承诺状态

    只允许两种状态转换:从挂起到履行,从挂起到拒绝。 没有其他转换是可能的,一旦转换完成,承诺值(或拒绝原因)不应改变。

    这是一个简单的实现,将遵守上述限制。 注释引用上述规范中的编号要求:

    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.2 then方法

    这是规范的核心。 上面的代码可被扩展以暴露then方法,它返回一个承诺,并且提供适当的异步执行then回调,只有一次,提供多个then调用,车削例外排斥,...等。

    因此,下面的代码添加了then方法,但也是一个单独定义的broadcast函数,因为它必须在任何状态变化时被调用:这不仅包括then方法的效果(承诺被添加到列表中),还包括resolvereject方法(状态和价值变化)。

    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承诺解决程序

    这是治疗那些thenables(或者甚至承诺)值的过程是不同的:而不是返回原样的值,程序将执行then该值的方法和异步满足与来自接收到的值的承诺then回调。 在规范中没有提到它,但是这不仅在then方法中执行,而且在主要承诺以这样的值解决时执行也很有趣。

    所以现有的resolve方法应该用这个“Promise Resolution Procedure”来代替,它将会调用原来的resolve方法。 原来的一个可以称为“履行”,以表明它将永远解决履行的承诺:

    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

    上面构建的构造函数创建的东西更像是一个Deferred对象,即暴露了resolvereject方法。 更糟的是, statusvalue属性是可写的。 所以,将它视为一个不安全的Deferred对象的构造函数更合乎逻辑,并且创建一个单独的Promise构造函数,该构造函数基于此构造函数,但只公开需要的:一个then方法和一个构造函数回调,可以访问resolvereject

    延迟对象可以在没有构造函数回调参数的情况下执行,并通过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;
    };
    
    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;
    }
    

    这个代码有几种可能的优化方式,例如使Deferred方法使用私有函数,并将相似的代码合并成较短的代码块,但现在它很清楚地显示了每个需求的覆盖范围。

    快乐的编码。


    这一切似乎都非常复杂。 我认为有一个非常简单的递归解决方案。 为了简洁起见,我将省略拒绝,但除了您停止链之外,它与解决方案几乎相同。

    var MyPromise = function(callback) {
      this.callbacks = [];
      callback(this.resolve.bind(this));
     }
    
    MyPromise.prototype.resolve = function(data) {
      var callback = this.callbacks.pop();
      var result =  callback(data);
    
      if (!result) return;
    
      if (result instanceof MyPromise) {
        var resolve = this.resolve.bind(this);
        return result.then(function(d) {
            return resolve(d);
        });
      }
    
      return this.resolve(result);
    
    }
    
    MyPromise.prototype.then = function(callback) {
      this.callbacks.unshift(callback);
      return this;
    }
    
    链接地址: http://www.djcxy.com/p/55499.html

    上一篇: Basic Javascript promise implementation attempt

    下一篇: How rsvp.js handles rejected promise with chain of failure callbacks