javascript 承诺/延迟库是如何实现的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17718673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 09:20:05  来源:igfitidea点击:

How is a promise/defer library implemented?

javascriptpromise

提问by Derek Chiang

How is a promise/defer library like qimplemented? I was trying to read the source code but found it pretty hard to understand, so I thought it'd be great if someone could explain to me, from a high level, what are the techniques used to implement promises in single-thread JS environments like Node and browsers.

q这样的 promise/defer 库是如何实现的?我试图阅读源代码,但发现它很难理解,所以我认为如果有人能从高层次向我解释在单线程 JS 环境中用于实现承诺的技术是什么,那就太好了像 Node 和浏览器。

回答by Kaizo

I find it harder to explain than to show an example, so here is a very simple implementation of what a defer/promise could be.

我发现解释比展示一个例子更难,所以这里有一个非常简单的 defer/promise 实现。

Disclaimer:This is not a functional implementation and some parts of the Promise/A specification are missing, This is just to explain the basis of the promises.

免责声明:这不是一个功能实现,缺少 Promise/A 规范的某些部分,这只是为了解释 Promise 的基础。

tl;dr:Go to the Create classes and examplesection to see full implementation.

tl;dr:转到创建类和示例部分以查看完整实现。

Promise:

承诺:

First we need to create a promise object with an array of callbacks. I'll start working with objects because it's clearer:

首先,我们需要创建一个带有回调数组的 promise 对象。我将开始使用对象,因为它更清晰:

var promise = {
  callbacks: []
}

now add callbacks with the method then:

现在使用该方法添加回调,然后:

var promise = {
  callbacks: [],
  then: function (callback) {
    callbacks.push(callback);
  }
}

And we need the error callbacks too:

我们也需要错误回调:

var promise = {
  okCallbacks: [],
  koCallbacks: [],
  then: function (okCallback, koCallback) {
    okCallbacks.push(okCallback);
    if (koCallback) {
      koCallbacks.push(koCallback);
    }
  }
}

Defer:

推迟:

Now create the defer object that will have a promise:

现在创建一个具有承诺的 defer 对象:

var defer = {
  promise: promise
};

The defer needs to be resolved:

需要解决的延迟:

var defer = {
  promise: promise,
  resolve: function (data) {
    this.promise.okCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(data)
      }, 0);
    });
  },
};

And needs to reject:

并且需要拒绝:

var defer = {
  promise: promise,
  resolve: function (data) {
    this.promise.okCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(data)
      }, 0);
    });
  },

  reject: function (error) {
    this.promise.koCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(error)
      }, 0);
    });
  }
};

Note that the callbacks are called in a timeout to allow the code be always asynchronous.

请注意,回调在超时时调用以允许代码始终异步。

And that's what a basic defer/promise implementation needs.

这就是基本的延迟/承诺实现所需要的。

Create classes and example:

创建类和示例:

Now lets convert both objects to classes, first the promise:

现在让我们将两个对象都转换为类,首先是承诺:

var Promise = function () {
  this.okCallbacks = [];
  this.koCallbacks = [];
};

Promise.prototype = {
  okCallbacks: null,
  koCallbacks: null,
  then: function (okCallback, koCallback) {
    okCallbacks.push(okCallback);
    if (koCallback) {
      koCallbacks.push(koCallback);
    }
  }
};

And now the defer:

现在推迟:

var Defer = function () {
  this.promise = new Promise();
};

Defer.prototype = {
  promise: null,
  resolve: function (data) {
    this.promise.okCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(data)
      }, 0);
    });
  },

  reject: function (error) {
    this.promise.koCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(error)
      }, 0);
    });
  }
};

And here is an example of use:

这是一个使用示例:

function test() {
  var defer = new Defer();
  // an example of an async call
  serverCall(function (request) {
    if (request.status === 200) {
      defer.resolve(request.responseText);
    } else {
      defer.reject(new Error("Status code was " + request.status));
    }
  });
  return defer.promise;
}

test().then(function (text) {
  alert(text);
}, function (error) {
  alert(error.message);
});

As you can see the basic parts are simple and small. It will grow when you add other options, for example multiple promise resolution:

正如您所看到的,基本部件既简单又小巧。当您添加其他选项时,它会增长,例如多个承诺解析:

Defer.all(promiseA, promiseB, promiseC).then()

or promise chaining:

或承诺链接:

getUserById(id).then(getFilesByUser).then(deleteFile).then(promptResult);

To read more about the specifications: CommonJS Promise Specification. Note that main libraries (Q, when.js, rsvp.js, node-promise, ...) follow Promises/Aspecification.

要阅读有关规范的更多信息:CommonJS Promise Specification。请注意,主要库(Q、when.js、rsvp.js、node-promise 等)遵循Promises/A规范。

Hope I was clear enough.

希望我说得够清楚了。

Edit:

编辑:

As asked in the comments, I've added two things in this version:

正如评论中所问,我在这个版本中添加了两件事:

  • The possibility to call then of a promise, no matter what status it has.
  • The possibility to chain promises.
  • 调用 then 的可能性,无论它处于什么状态。
  • 链接承诺的可能性。

To be able to call the promise when resolved you need to add the status to the promise, and when the then is called check that status. If the status is resolved or rejected just execute the callback with its data or error.

为了能够在解决时调用承诺,您需要将状态添加到承诺中,然后在调用 then 时检查该状态。如果状态已解决或被拒绝,只需执行带有数据或错误的回调。

To be able to chain promises you need to generate a new defer for each call to thenand, when the promise is resolved/rejected, resolve/reject the new promise with the result of the callback. So when the promise is done, if the callback returns a new promise it is bound to the promise returned with the then(). If not, the promise is resolved with the result of the callback.

为了能够链接承诺,您需要为每次调用生成一个新的延迟,then并且当承诺被解决/拒绝时,使用回调的结果解决/拒绝新的承诺。所以当promise完成后,如果回调返回一个新的promise,它就会绑定到返回的promise上then()。如果不是,则使用回调的结果解决承诺。

Here is the promise:

这是承诺:

var Promise = function () {
  this.okCallbacks = [];
  this.koCallbacks = [];
};

Promise.prototype = {
  okCallbacks: null,
  koCallbacks: null,
  status: 'pending',
  error: null,

  then: function (okCallback, koCallback) {
    var defer = new Defer();

    // Add callbacks to the arrays with the defer binded to these callbacks
    this.okCallbacks.push({
      func: okCallback,
      defer: defer
    });

    if (koCallback) {
      this.koCallbacks.push({
        func: koCallback,
        defer: defer
      });
    }

    // Check if the promise is not pending. If not call the callback
    if (this.status === 'resolved') {
      this.executeCallback({
        func: okCallback,
        defer: defer
      }, this.data)
    } else if(this.status === 'rejected') {
      this.executeCallback({
        func: koCallback,
        defer: defer
      }, this.error)
    }

    return defer.promise;
  },

  executeCallback: function (callbackData, result) {
    window.setTimeout(function () {
      var res = callbackData.func(result);
      if (res instanceof Promise) {
        callbackData.defer.bind(res);
      } else {
        callbackData.defer.resolve(res);
      }
    }, 0);
  }
};

And the defer:

和延迟:

var Defer = function () {
  this.promise = new Promise();
};

Defer.prototype = {
  promise: null,
  resolve: function (data) {
    var promise = this.promise;
    promise.data = data;
    promise.status = 'resolved';
    promise.okCallbacks.forEach(function(callbackData) {
      promise.executeCallback(callbackData, data);
    });
  },

  reject: function (error) {
    var promise = this.promise;
    promise.error = error;
    promise.status = 'rejected';
    promise.koCallbacks.forEach(function(callbackData) {
      promise.executeCallback(callbackData, error);
    });
  },

  // Make this promise behave like another promise:
  // When the other promise is resolved/rejected this is also resolved/rejected
  // with the same data
  bind: function (promise) {
    var that = this;
    promise.then(function (res) {
      that.resolve(res);
    }, function (err) {
      that.reject(err);
    })
  }
};

As you can see, it has grown quite a bit.

如您所见,它已经增长了很多。

回答by ForbesLindesay

Q is a very complex promise library in terms of implementation because it aims to support pipelining and RPC type scenarios. I have my own very bare bones implementation of the Promises/A+specification here.

Q 在实现方面是一个非常复杂的 promise 库,因为它旨在支持流水线和 RPC 类型的场景。我有我自己的非常裸露的骨头实现的承诺/ A +规格在这里

In principle it's quite simple. Before the promise is settled/resolved, you keep a record of any callbacks or errbacks by pushing them into an array. When the promise is settled you call the appropriate callbacks or errbacks and record what result the promise was settled with (and whether it was fulfilled or rejected). After it's settled, you just call the callbacks or errbacks with the stored result.

原则上很简单。在承诺被解决/解决之前,您可以通过将它们推送到数组中来记录任何回调或错误返回。当 promise 被解决时,你调用适当的回调或 errbacks 并记录 promise 的解决结果(以及它是被实现还是被拒绝)。确定后,您只需使用存储的结果调用回调或错误返回。

That gives you aproximately the semantics of done. To build thenyou just have to return a new promise that is resolved with the result of calling the callbacks/errbacks.

这为您提供了大致的语义done。要构建,then您只需要返回一个新的承诺,该承诺通过调用回调/errbacks 的结果得到解决。

If you're interested in a full explenation of the reasonning behind the development of a full on promise implementation with support for RPC and pipelining like Q, you can read kriskowal's reasonning here. It's a really nice graduated approach that I can't recommend highly enough if you are thinking of implementing promises. It's probably worth a read even if you're just going to be using a promise library.

如果您对开发支持 RPC 和管道(如 Q)的完整承诺实现背后的推理感兴趣,您可以在此处阅读 kriskowal 的推理。这是一种非常好的渐进式方法,如果您正在考虑实施承诺,我不能高度推荐。即使您只是打算使用 Promise 库,它也可能值得一读。

回答by Kris Kowal

As Forbes mentions in his answer, I chronicled many of the design decisions involved in making a library like Q, here https://github.com/kriskowal/q/tree/v1/design. Suffice it to say, there are levels of a promise library, and lots of libraries that stop at various levels.

正如福布斯在他的回答中提到的那样,我在https://github.com/kriskowal/q/tree/v1/design中记录了制作像 Q 这样的库所涉及的许多设计决策。可以这么说,promise 库有多个级别,并且有很多库停在不同级别。

At the first level, captured by the Promises/A+ specification, a promise is a proxy for an eventual result and is suitable for managing “local asynchrony”. That is, it is suitable for ensuring that work occurs in the right order, and for ensuring that it is simple and straight-forward to listen for the result of an operation regardless of whether it already settled, or will occur in the future. It also makes it just as simple for one or many parties to subscribe to an eventual result.

在第一层,由 Promises/A+ 规范捕获,promise 是最终结果的代理,适用于管理“本地异步”。也就是说,它适用于确保工作以正确的顺序发生,并适用于确保无论操作的结果是已经解决还是将来会发生,都可以简单直接地监听操作的结果。它还使一方或多方订阅最终结果变得同样简单。

Q, as I have implemented it, provides promises that are proxies for eventual, remote, or eventual+remote results. To that end, it's design is inverted, with different implementations for promises—deferred promises, fulfilled promises, rejected promises, and promises for remote objects (the last being implemented in Q-Connection). They all share the same interface and work by sending and receiving messages like "then" (which is sufficient for Promises/A+) but also "get" and "invoke". So, Q is about “distributed asynchrony”, and exists on another layer.

Q,正如我已经实现的那样,提供了作为最终、远程或最终+远程结果的代理的承诺。为此,它的设计是颠倒的,有不同的承诺实现——延迟的承诺、履行的承诺、拒绝的承诺和远程对象的承诺(最后一个在 Q-Connection 中实现)。它们都共享相同的接口,并通过发送和接收诸如“then”(这对于 Promises/A+ 就足够了)以及“get”和“invoke”之类的消息来工作。所以,Q是关于“分布式异步”的,存在于另一层。

However, Q was actually taken down from a higher layer, where promises are used for managing distributed asynchrony among mutually suspicious partieslike you, a merchant, a bank, Facebook, the government—not enemies, maybe even friends, but sometimes with conflicts of interest. The Q that I implemented is designed to be API compatible with hardened security promises (which is the reason for separating promiseand resolve), with the hope that it would introduce people to promises, train them in using this API, and allow them to take their code with them if they need to use promises in secure mashups in the future.

然而,Q 实际上是从更高层撤下的,在那里 Promise 用于管理相互怀疑的各方(例如您、商人、银行、Facebook、政府)之间的分布式异步- 不是敌人,甚至可能是朋友,但有时会发生冲突兴趣。我实现的 Q 被设计成与强化安全承诺的 API 兼容(这就是将promise和分开的原因resolve),希望它能向人们介绍承诺,训练他们使用这个 API,并允许他们使用他们的代码如果他们将来需要在安全的 mashup 中使用 promise,请与他们联系。

Of course, there are trade-offs as you move up the layers, usually in speed. So, promises implementations can also be designed to co-exist. This is where the concept of a “thenable”enters. Promise libraries at each layer can be designed to consume promises from any other layer, so multiple implementations can coexist, and users can buy only what they need.

当然,当您向上移动层时,通常会在速度方面进行权衡。因此,promise 实现也可以设计为共存。这就是“thenable”的概念出现的地方。每一层的 Promise 库都可以设计为消费来自任何其他层的 Promise,因此多个实现可以共存,用户可以只购买他们需要的东西。

All this said, there is no excuse for being difficult to read. Domenic and I are working on a version of Q that will be more modular and approachable, with some of its distracting dependencies and work-arounds moved into other modules and packages. Thankfully folks like Forbes, Crockford, and others have filled in the educational gap by making simpler libraries.

所有这一切都说,没有理由难以阅读。Domenic 和我正在开发一个更加模块化和易于使用的 Q 版本,其中一些分散注意力的依赖项和变通方法被转移到其他模块和包中。值得庆幸的是,像ForbesCrockford和其他人这样的人通过制作更简单的图书馆填补了教育空白。

回答by Bergi

First make sure you're understanding how Promises are supposed to work. Have a look at the CommonJs Promisesproposalsand the Promises/A+ specificationfor that.

首先确保您了解 Promise 应该如何工作。查看CommonJs Promises提案Promises/A+ 规范

There are two basic concepts that can be implemented each in a few simple lines:

有两个基本概念可以用几行简单的代码实现:

  • A Promise does asynchronously get resolved with the result. Adding callbacks is a transparent action - independent from whether the promise is resolved already or not, they will get called with the result once it is available.

    function Deferred() {
        var callbacks = [], // list of callbacks
            result; // the resolve arguments or undefined until they're available
        this.resolve = function() {
            if (result) return; // if already settled, abort
            result = arguments; // settle the result
            for (var c;c=callbacks.shift();) // execute stored callbacks
                c.apply(null, result);
        });
        // create Promise interface with a function to add callbacks:
        this.promise = new Promise(function add(c) {
            if (result) // when results are available
                c.apply(null, result); // call it immediately
            else
                callbacks.push(c); // put it on the list to be executed later
        });
    }
    // just an interface for inheritance
    function Promise(add) {
        this.addCallback = add;
    }
    
  • Promises have a thenmethod that allows chaining them. I takes a callback and returns a new Promise which will get resolved with the result of that callback after it was invoked with the first promise's result. If the callback returns a Promise, it will get assimilated instead of getting nested.

    Promise.prototype.then = function(fn) {
        var dfd = new Deferred(); // create a new result Deferred
        this.addCallback(function() { // when `this` resolves…
            // execute the callback with the results
            var result = fn.apply(null, arguments);
            // check whether it returned a promise
            if (result instanceof Promise)
                result.addCallback(dfd.resolve); // then hook the resolution on it
            else
                dfd.resolve(result); // resolve the new promise immediately 
            });
        });
        // and return the new Promise
        return dfd.promise;
    };
    
  • 一个 Promise 会异步地得到结果。添加回调是一个透明的操作——与承诺是否已经解决无关,一旦结果可用,它们就会被调用。

    function Deferred() {
        var callbacks = [], // list of callbacks
            result; // the resolve arguments or undefined until they're available
        this.resolve = function() {
            if (result) return; // if already settled, abort
            result = arguments; // settle the result
            for (var c;c=callbacks.shift();) // execute stored callbacks
                c.apply(null, result);
        });
        // create Promise interface with a function to add callbacks:
        this.promise = new Promise(function add(c) {
            if (result) // when results are available
                c.apply(null, result); // call it immediately
            else
                callbacks.push(c); // put it on the list to be executed later
        });
    }
    // just an interface for inheritance
    function Promise(add) {
        this.addCallback = add;
    }
    
  • Promise 有一种then方法可以将它们链接起来。我接受一个回调并返回一个新的 Promise,它会在第一个 Promise 的结果被调用后用该回调的结果解决。如果回调返回一个 Promise,它将被同化而不是被嵌套。

    Promise.prototype.then = function(fn) {
        var dfd = new Deferred(); // create a new result Deferred
        this.addCallback(function() { // when `this` resolves…
            // execute the callback with the results
            var result = fn.apply(null, arguments);
            // check whether it returned a promise
            if (result instanceof Promise)
                result.addCallback(dfd.resolve); // then hook the resolution on it
            else
                dfd.resolve(result); // resolve the new promise immediately 
            });
        });
        // and return the new Promise
        return dfd.promise;
    };
    

Further concepts would be maintaining a separate errorstate (with an extra callback for it) and catching exceptions in the handlers, or guaranteeing asynchronity for the callbacks. Once you add those, you've got a fully functional Promise implementation.

进一步的概念是维护一个单独的错误状态(带有一个额外的回调)并在处理程序中捕获异常,或者保证回调的异步性。一旦你添加了这些,你就有了一个功能齐全的 Promise 实现。

Here is the error thing written out. It unfortunately is pretty repetitive; you can do better by using extra closures but then it get's really really hard to understand.

这是写出的错误内容。不幸的是,它非常重复;你可以通过使用额外的闭包来做得更好,但它真的很难理解。

function Deferred() {
    var callbacks = [], // list of callbacks
        errbacks = [], // list of errbacks
        value, // the fulfill arguments or undefined until they're available
        reason; // the error arguments or undefined until they're available
    this.fulfill = function() {
        if (reason || value) return false; // can't change state
        value = arguments; // settle the result
        for (var c;c=callbacks.shift();)
            c.apply(null, value);
        errbacks.length = 0; // clear stored errbacks
    });
    this.reject = function() {
        if (value || reason) return false; // can't change state
        reason = arguments; // settle the errror
        for (var c;c=errbacks.shift();)
            c.apply(null, reason);
        callbacks.length = 0; // clear stored callbacks
    });
    this.promise = new Promise(function add(c) {
        if (reason) return; // nothing to do
        if (value)
            c.apply(null, value);
        else
            callbacks.push(c);
    }, function add(c) {
        if (value) return; // nothing to do
        if (reason)
            c.apply(null, reason);
        else
            errbacks.push(c);
    });
}
function Promise(addC, addE) {
    this.addCallback = addC;
    this.addErrback = addE;
}
Promise.prototype.then = function(fn, err) {
    var dfd = new Deferred();
    this.addCallback(function() { // when `this` is fulfilled…
        try {
            var result = fn.apply(null, arguments);
            if (result instanceof Promise) {
                result.addCallback(dfd.fulfill);
                result.addErrback(dfd.reject);
            } else
                dfd.fulfill(result);
        } catch(e) { // when an exception was thrown
            dfd.reject(e);
        }
    });
    this.addErrback(err ? function() { // when `this` is rejected…
        try {
            var result = err.apply(null, arguments);
            if (result instanceof Promise) {
                result.addCallback(dfd.fulfill);
                result.addErrback(dfd.reject);
            } else
                dfd.fulfill(result);
        } catch(e) { // when an exception was re-thrown
            dfd.reject(e);
        }
    } : dfd.reject); // when no `err` handler is passed then just propagate
    return dfd.promise;
};

回答by AbdulFattah Popoola

You might want to check out the blog poston Adehun.

您可能想查看有关 Adehun的博客文章

Adehun is an extremely lightweight implementation (about 166 LOC) and very useful for learning how to implement the Promise/A+ spec.

Adehun 是一个非常轻量级的实现(大约 166 LOC),对于学习如何实现 Promise/A+ 规范非常有用。

Disclaimer: I wrote the blog post but the blog post does explain all about Adehun.

免责声明:我写了博客文章,但博客文章确实解释了关于 Adehun 的所有内容。

The Transition function – Gatekeeper for State Transition

转换功能——状态转换的守门人

Gatekeeper function; ensures that state transitions occur when all required conditions are met.

看门人功能;确保在满足所有必需条件时发生状态转换。

If conditions are met, this function updates the promise's state and value. It then triggers the process function for further processing.

如果满足条件,此函数会更新承诺的状态和值。然后它会触发流程功能以进行进一步处理。

The process function carries out the right action based on the transition (e.g. pending to fulfilled) and is explained later.

流程功能根据转换(例如待完成)执行正确的操作,稍后解释。

function transition (state, value) {
  if (this.state === state ||
    this.state !== validStates.PENDING ||
    !isValidState(state)) {
      return;
    }

  this.value = value;
  this.state = state;
  this.process();
}

The Then function

然后函数

The then function takes in two optional arguments (onFulfill and onReject handlers) and must return a new promise. Two major requirements:

then 函数接受两个可选参数(onFulfill 和 onReject 处理程序)并且必须返回一个新的承诺。两个主要要求:

  1. The base promise (the one on which then is called) needs to create a new promise using the passed in handlers; the base also stores an internal reference to this created promise so it can be invoked once the base promise is fulfilled/rejected.

  2. If the base promise is settled (i.e. fulfilled or rejected), then the appropriate handler should be called immediately. Adehun.js handles this scenario by calling process in the then function.

  1. 基础承诺(然后被调用的承诺)需要使用传入的处理程序创建一个新的承诺;基础还存储了对这个创建的承诺的内部引用,因此一旦基础承诺被实现/拒绝就可以调用它。

  2. 如果基本承诺已解决(即完成或拒绝),则应立即调用适当的处理程序。Adehun.js 通过在 then 函数中调用 process 来处理这种情况。

``

``

function then(onFulfilled, onRejected) {
    var queuedPromise = new Adehun();
    if (Utils.isFunction(onFulfilled)) {
        queuedPromise.handlers.fulfill = onFulfilled;
    }

    if (Utils.isFunction(onRejected)) {
        queuedPromise.handlers.reject = onRejected;
    }

    this.queue.push(queuedPromise);
    this.process();

    return queuedPromise;
}`

The Process function – Processing Transitions

处理功能 - 处理转换

This is called after state transitions or when the then function is invoked. Thus it needs to check for pending promises since it might have been invoked from the then function.

这是在状态转换后或调用 then 函数时调用的。因此它需要检查挂起的承诺,因为它可能是从 then 函数中调用的。

Process runs the Promise Resolution procedure on all internally stored promises (i.e. those that were attached to the base promise through the then function) and enforces the following Promise/A+ requirements:

Process 对所有内部存储的承诺(即那些通过 then 函数附加到基本承诺的承诺)运行承诺解析过程,并强制执行以下 Promise/A+ 要求:

  1. Invoking the handlers asynchronously using the Utils.runAsync helper (a thin wrapper around setTimeout (setImmediate will also work)).

  2. Creating fallback handlers for the onSuccess and onReject handlers if they are missing.

  3. Selecting the correct handler function based on the promise state e.g. fulfilled or rejected.

  4. Applying the handler to the base promise's value. The value of this operation is passed to the Resolve function to complete the promise processing cycle.

  5. If an error occurs, then the attached promise is immediately rejected.

    function process() { var that = this, fulfillFallBack = function(value) { return value; }, rejectFallBack = function(reason) { throw reason; };

    if (this.state === validStates.PENDING) {
        return;
    }
    
    Utils.runAsync(function() {
        while (that.queue.length) {
            var queuedP = that.queue.shift(),
                handler = null,
                value;
    
            if (that.state === validStates.FULFILLED) {
                handler = queuedP.handlers.fulfill ||
                    fulfillFallBack;
            }
            if (that.state === validStates.REJECTED) {
                handler = queuedP.handlers.reject ||
                    rejectFallBack;
            }
    
            try {
                value = handler(that.value);
            } catch (e) {
                queuedP.reject(e);
                continue;
            }
    
            Resolve(queuedP, value);
        }
    });
    

    }

  1. 使用 Utils.runAsync 帮助程序(一个围绕 setTimeout 的薄包装器(setImmediate 也可以工作))异步调用处理程序。

  2. 如果 onSuccess 和 onReject 处理程序丢失,则为它们创建回退处理程序。

  3. 根据承诺状态(例如已完成或已拒绝)选择正确的处理程序函数。

  4. 将处理程序应用于基本承诺的值。这个操作的值传递给Resolve函数来完成promise处理循环。

  5. 如果发生错误,则附加的承诺会立即被拒绝。

    function process() { var that = this,fulfillback = function(value) { return value; } }, rejectFallBack = function(reason) { throw reason; };

    if (this.state === validStates.PENDING) {
        return;
    }
    
    Utils.runAsync(function() {
        while (that.queue.length) {
            var queuedP = that.queue.shift(),
                handler = null,
                value;
    
            if (that.state === validStates.FULFILLED) {
                handler = queuedP.handlers.fulfill ||
                    fulfillFallBack;
            }
            if (that.state === validStates.REJECTED) {
                handler = queuedP.handlers.reject ||
                    rejectFallBack;
            }
    
            try {
                value = handler(that.value);
            } catch (e) {
                queuedP.reject(e);
                continue;
            }
    
            Resolve(queuedP, value);
        }
    });
    

    }

The Resolve function – Resolving Promises

Resolve 函数——解析承诺

This is probably the most important part of the promise implementation since it handles promise resolution. It accepts two parameters – the promise and its resolution value.

这可能是 promise 实现中最重要的部分,因为它处理 promise 解析。它接受两个参数——promise 和它的分辨率值。

While there are lots of checks for various possible resolution values; the interesting resolution scenarios are two – those involving a promise being passed in and a thenable (an object with a then value).

虽然对各种可能的分辨率值进行了大量检查;有趣的解决方案有两种——涉及传入的承诺和 thenable(具有 then 值的对象)。

  1. Passing in a Promise value
  1. 传递一个 Promise 值

If the resolution value is another promise, then the promise must adopt this resolution value's state. Since this resolution value can be pending or settled, the easiest way to do this is to attach a new then handler to the resolution value and handle the original promise therein. Whenever it settles, then the original promise will be resolved or rejected.

如果分辨率值是另一个承诺,那么承诺必须采用这个分辨率值的状态。由于此解析值可以挂起或结算,因此最简单的方法是将新的 then 处理程序附加到解析值并处理其中的原始承诺。每当它解决时,原始承诺将被解决或拒绝。

  1. Passing in a thenable value
  1. 传递一个 thenable 值

The catch here is that the thenable value's then function must be invoked only once (a good use for the once wrapper from functional programming). Likewise, if the retrieval of the then function throws an Exception, the promise is to be rejected immediately.

这里的问题是 thenable 值的 then 函数必须只调用一次(对于函数式编程中的 once 包装器来说是一个很好的用途)。同样,如果 then 函数的检索抛出异常,则承诺将立即被拒绝。

Like before, the then function is invoked with functions that ultimately resolve or reject the promise but the difference here is the called flag which is set on the first call and turns subsequent calls are no ops.

像以前一样, then 函数被调用,最终解析或拒绝承诺的函数,但这里的区别是在第一次调用时设置的被调用标志,并且将后续调用变为无操作。

function Resolve(promise, x) {
  if (promise === x) {
    var msg = "Promise can't be value";
    promise.reject(new TypeError(msg));
  }
  else if (Utils.isPromise(x)) {
    if (x.state === validStates.PENDING){
      x.then(function (val) {
        Resolve(promise, val);
      }, function (reason) {
        promise.reject(reason);
      });
    } else {
      promise.transition(x.state, x.value);
    }
  }
  else if (Utils.isObject(x) ||
           Utils.isFunction(x)) {
    var called = false,
        thenHandler;

    try {
      thenHandler = x.then;

      if (Utils.isFunction(thenHandler)){
        thenHandler.call(x,
          function (y) {
            if (!called) {
              Resolve(promise, y);
              called = true;
            }
          }, function (r) {
            if (!called) {
              promise.reject(r);
              called = true;
            }
       });
     } else {
       promise.fulfill(x);
       called = true;
     }
   } catch (e) {
     if (!called) {
       promise.reject(e);
       called = true;
     }
   }
 }
 else {
   promise.fulfill(x);
 }
}

The Promise Constructor

Promise 构造器

And this is the one that puts it all together. The fulfill and reject functions are syntactic sugar that pass no-op functions to resolve and reject.

而这就是将这一切结合在一起的一个。履行和拒绝函数是语法糖,通过无操作函数来解决和拒绝。

var Adehun = function (fn) {
 var that = this;

 this.value = null;
 this.state = validStates.PENDING;
 this.queue = [];
 this.handlers = {
   fulfill : null,
   reject : null
 };

 if (fn) {
   fn(function (value) {
     Resolve(that, value);
   }, function (reason) {
     that.reject(reason);
   });
 }
};

I hope this helped shed more light into the way promises work.

我希望这有助于更多地了解 Promise 的工作方式。