当前位置: 首页 > 知识库问答 >
问题:

基本Javascriptpromise实现尝试

康恩
2023-03-14

为了更好地理解Promission在Javascript中的工作方式,我决定尝试一下,自己编写基本的实现代码。

基本上,我想实现以函数为参数的Promissions对象(我在代码中称之为Aaa)。此函数可以调用resolve来resolve承诺,或者调用reject来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(Promise)以便将它们链接起来。下面的代码使用上面创建的promise并链接then回调。每个然后返回新的promise,在这种情况下,它似乎运行良好:

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的调用不应该被调用,直到我们刚刚添加的返回承诺被解析。

如何才能最好地实施这一目标?

共有2个答案

宰父飞翼
2023-03-14

(若要获得完整的承诺实现,请向下滚动)。

有几个问题,但我认为您的代码中的主要错误是,您采用了给then方法的参数,并将其作为参数传递给promise构造函数:

this.then=function(resolve,reject) {
    var nextPromise=new Aaa(resolve,true);
    // ...

虽然这两个参数都是回调函数,但它们具有不同的签名,并具有完全不同的用途:

  • promise构造函数的参数是一个要立即同步执行的回调函数。一个函数作为第一个参数传递给它,您可以用它解析您正在创建的承诺。
  • then方法的(第一个)参数是一个回调函数,它只有在解析基本承诺时才会异步执行,并且解析的值作为参数传递给它。

您还可以在代码中看到不同之处,在代码中,您将参数存储为构造函数的f属性。这两者都有:

t.thens[i].f(g);

...其中g是解析值,但也是:

this.f(this.resolve,this.reject); 

…其中参数是函数。当您创建nextPromise时,实际上您将首先使用这两个参数调用f,然后使用g参数调用。

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

只允许两个状态转换:从挂起到已完成,以及从挂起到已拒绝。不应该有其他过渡,并且一旦已经执行了过渡,承诺值(或拒绝理由)不应该改变。

这里有一个简单的实现,它将遵守上述限制。注释参考了上述规范中编号的要求:

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方法,它是承诺的关键:

这是规范的核心。可以扩展上述代码以公开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:注释处,必须调用所谓的承诺解析过程:

这是一个以不同方式对待thenables(甚至承诺)值的过程:该过程将对该值执行then方法,并使用从该then回调接收的值异步实现承诺,而不是按原样返回该值。规范中没有提到它,但这一点不仅在then方法中执行,而且在使用这样的值解析主承诺时也是很有趣的。

因此现有的resolve方法应该替换为这个“Promise Resolution Procedure”,它将调用原来的方法。最初的一个可以被称为“履行”,表示它将解决承诺始终履行:

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);
    }
}

现在这是符合承诺/A+的,至少它通过了测试套件。然而,Promise对象公开了太多的方法和属性:

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

然后,延迟对象可以不使用构造函数回调参数,并通过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;
};

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;
}

对这段代码有几种可能的优化,比如使延迟方法成为私有函数,以及将相似的代码合并到更短的代码块中,但就目前的情况来看,它非常清楚地显示了每个需求的覆盖范围。

快乐编码。

杨高翰
2023-03-14

有很多案子你不在这里处理。最好的方法是首先将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 (value && (typeof value === 'object' || typeof value === '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如何接收一个承诺作为其参数,但一个承诺永远不能用另一个承诺来实现。所以我们要处理这个特殊的案子。

还要注意,一个承诺只能被履行/拒绝一次。我们还存在第三方承诺可能行为不端的问题,我们应该保护我们的代码不受此影响。由于这个原因,我没有从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,因为我们有另一个不受信任的解析器。fn可能多次调用resolvereject,并且可能引发错误。我们需要处理所有这些情况(这就是doResolve所做的)。

我们现在已经有了完成的状态机,但是我们还没有公开任何关于它处于什么状态的信息。让我们尝试添加一个.done(onfullettle,onRejected)方法,该方法与.then方法类似,只不过它不返回承诺,也不处理由onfullettleonRejected引发的错误。

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实现,但是,正如您在构建自己的实现时已经注意到的,我们需要一个返回promise的.then方法。

我们可以通过.done轻松地构建此功能:

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实现(尽管就我所知它是正确的)。您应该根据Promission/A+测试套件(https://github.com/promission-applus/promission-tests)测试您构建的任何实现,并且可能还会发现Promission/A+规范(https://github.com/promission-applus/promission-spec)对于确定算法的任何特定部分的正确行为很有用。作为最后一个资源,promise是promise规范的一个非常小的实现。

 类似资料:
  • 概括来说,fpm的实现就是创建一个master进程,在master进程中创建并监听socket,然后fork出多个子进程,这些子进程各自accept请求,子进程的处理非常简单,它在启动后阻塞在accept上,有请求到达后开始读取请求数据,读取完成后开始处理然后再返回,在这期间是不会接收其它请求的,也就是说fpm的子进程同时只能响应一个请求,只有把这个请求处理完成后才会accept下一个请求,这一点

  • 本文向大家介绍Javascript实现基本运算器,包括了Javascript实现基本运算器的使用技巧和注意事项,需要的朋友参考一下 用Javascript实现一个基本的运算器,具体内容如下 使用表格布局,JS添加事件 计算器的”c”功能为清屏;”d”功能为删除一个数; 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 问题内容: 我有两个要在Test Suite中一起运行的测试用例(两个不同的文件)。我可以仅通过“正常”运行python来运行测试,但是当我选择运行python单元测试时,它说运行0次测试。现在,我只是想至少进行一项测试以正确运行。 这是我的测试用例设置的示例 我该怎么做才能正确地完成这项工作? 问题答案: 您想使用测试服。因此,您无需调用unittest.main()。测试套件的使用应如下所示:

  • 我是android的新手,所以我希望我听起来不会太笨,也就是说,我做了一个片段,专门为XML中的按钮实现了OnclickListener。我需要默认的onclick函数来将按钮的文本保存为字符串,但是我还没有弄清楚如何从视图中检索按钮的文本。这将帮助我为我要做的每一个按钮做一个if语句。有什么建议吗?

  • 本文向大家介绍Python基于Tkinter实现的记事本实例,包括了Python基于Tkinter实现的记事本实例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python基于Tkinter实现的记事本。分享给大家供大家参考。具体如下: 希望本文所述对大家的Python程序设计有所帮助。

  • 本文向大家介绍Openlayers实现地图的基本操作,包括了Openlayers实现地图的基本操作的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Openlayers实现地图基本操作的具体代码,供大家参考,具体内容如下 1、新建一个html页面,引入ol.js和ol.css文件,然后在body中创建一个Div标签和4个Button按钮,用来实现地图的放大、缩小、平移等功能; 2、代码