概念 - 提炼承诺如何运作?

11 javascript

我看过很多实现,它们看起来都很不一样,我无法真正提炼出承诺的本质.

如果我不得不猜测它只是一个在回调触发时运行的函数.

有人可以在几行代码中实现最基本的承诺.

例如,从这个答案

片段1

var a1 = getPromiseForAjaxResult(ressource1url);
a1.then(function(res) {
    append(res);
    return a2;
});
Run Code Online (Sandbox Code Playgroud)

如何传递函数以then了解何时运行.

也就是说,它如何传递回ajax在完成时触发的回调代码.

片段2

// generic ajax call with configuration information and callback function
ajax(config_info, function() {
    // ajax completed, callback is firing.
});
Run Code Online (Sandbox Code Playgroud)

这两个片段有何关联?

猜测:

// how to implement this

(function () {
    var publik = {};
        _private;
    publik.then = function(func){
        _private = func;
    };
    publik.getPromise = function(func){
        // ??
    };
    // ??
}())
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 25

从根本上说,一个承诺只是一个对象,它有一个标志,说明它是否已经解决,以及它维护的一系列功能,以便在结算时通知.代码有时可以说不仅仅是单词,所以这里有一个非常基本的,不现实世界的例子,纯粹是为了帮助传达这些概念:

// See notes following the code for why this isn't real-world code
function Promise() {
    this.settled = false;
    this.settledValue = null;
    this.callbacks = [];
}
Promise.prototype.then = function(f) {
    if (this.settled) {
        f(this.settledValue);                // See notes 1 and 2
    } else {
        this.callbacks.push(f);
    }
                                             // See note 3 about `then`
                                             // needing a return value
};
Promise.prototype.settle = function(value) { // See notes 4 and 5
    var callback;

    if (!this.settled) {
        this.settled = true;
        this.settledValue = value;
        while (this.callbacks.length) {
            callback = this.callbacks.pop();
            callback(this.settledValue);      // See notes 1 and 2
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

所以Promise保持状态,以及在承诺结算时调用的函数.解决 promise 的行为通常是Promise对象本身的外部(当然,这取决于实际使用,你可以将它们组合起来 - 例如,与jQuery的ajax[ jqXHR]对象一样).

同样,上述内容纯粹是概念性的,并且缺少必须在任何现实世界的承诺实现中出现的几个重要事项,以使其有用:

  1. then并且settle应该始终异步调用回调,即使承诺已经解决.then应该因为否则调用者不知道回调是否是异步的.settle应该因为回调之前不应该运行回调settle.(ES2015承诺做这两件事.jQuery Deferred没有.)

  2. then并且settle应该确保回调中的失败(例如,异常)不会直接传播到代码调用thensettle.这与上面的#1部分相关,对于下面的#3更是如此.

  3. then应该根据调用回调的结果(然后或稍后)返回一个新的 promise.这对于编写承诺操作非常重要,但会使上述内容复杂化.任何合理的承诺都会实现.

  4. 我们需要不同类型的"结算"操作:"解决"(基础操作成功)和"拒绝"(失败).某些用例可能包含更多状态,但已解决和拒绝是最基本的两种状态.(ES2015的承诺已经解决并拒绝.)

  5. 我们可以做settle(或单独的resolvereject)以某种方式私有的,所以只有承诺的创建者可以解决.(ES2015承诺 - 以及其他几个 - 通过让Promise构造函数接受一个接收resolvereject作为参数值的回调来做到这一点,因此只有该回调中的代码才能解析或拒绝[除非回调中的代码以某种方式使它们公开].)

等等


Ber*_*rgi 11

有人可以在几行中实现最基本的承诺吗?

这里是:

function Promise(fn) {
    // takes a function as an argument that gets the fullfiller
    var callbacks = [], result;
    fn(function fulfill() {
        if (result) return;
        result = arguments;
        for (var c;c=callbacks.shift();)
            c.apply(null, arguments);
    });
    this.addCallback = function(c) {
        if (result)
            c.apply(null, result)
        else
            callbacks.push(c);
    }
}
Run Code Online (Sandbox Code Playgroud)

附加then链接(您需要答案):

Promise.prototype.then = function(fn) {
    var that = this;
    return new Promise(function(c){
        that.addCallback(function() {
            var result = fn.apply(null, arguments);
            if (result instanceof Promise)
                result.addCallback(c);
            else
                c(result);
        });
    });
};
Run Code Online (Sandbox Code Playgroud)

这两个片段有何关联?

ajaxgetPromiseForAjaxResult函数中调用:

function getPromiseForAjaxResult(ressource) {
    return new Promise(function(callback) {
        ajax({url:ressource}, callback);
    });
}
Run Code Online (Sandbox Code Playgroud)