12

私は多くの実装を見てきましたが、それらはすべて非常に異なって見えるため、promise の本質が何であるかを抽出することはできません。

私が推測しなければならなかったのは、コールバックが発生したときに実行される単なる関数です。

誰かがチェーンなしで数行のコードで最も基本的な約束を実装できますか?

たとえば、この回答から

スニペット 1

var a1 = getPromiseForAjaxResult(ressource1url);
a1.then(function(res) {
    append(res);
    return a2;
});

thenいつ実行するかを知るために関数がどのように渡されますか。

つまり、完了時に ajax が起動するコールバック コードにどのように戻されるのかということです。

スニペット 2

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

これら 2 つのスニペットはどのように関連していますか?

推測:

// how to implement this

(function () {
    var publik = {};
        _private;
    publik.then = function(func){
        _private = func;
    };
    publik.getPromise = function(func){
        // ??
    };
    // ??
}())
4

6 に答える 6

27

基本的に、promise は、解決されたかどうかを示すフラグと、解決されたかどうかを通知するために維持する関数のリストを持つ単なるオブジェクトです。コードは言葉以上のことを伝える場合があるため、概念を伝えるために純粋に意図された、非常に基本的な非現実的な例を次に示します。

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

したがって、Promiseは状態と、promise が解決されたときに呼び出す関数を保持します。promise を解決する行為は、通常、オブジェクト自体の外部にありPromiseます (もちろん、実際の使用に依存しますが、それらを組み合わせることもできます — たとえば、jQuery のajax[ jqXHR] オブジェクトのように)。

繰り返しますが、上記は純粋に概念的なものであり、それが有用であるためには、実際の約束の実装に存在しなければならないいくつかの重要なものが欠けています:

  1. thenpromise が既に解決されている場合でも、コールバックを常にsettle非同期で呼び出す必要があります。そうしないと、呼び出し元はコールバックが非同期になるかどうかわからないためです。afterが戻るまでコールバックが実行されないためです。(ES2015 の promise はこれらの両方を行います。jQuery の promise は行いません。)thensettlesettleDeferred

  2. thenまた、コールバックの失敗 (例: 例外) がorsettleを呼び出すコードに直接伝播されないようにする必要があります。これは上記の #1 に部分的に関連しており、以下の #3 にさらに関連しています。thensettle

  3. thenコールバックを呼び出した結果に基づいて、新しいpromise を返す必要があります (その後)。これは、promise 化された操作を構成する上でかなり基本的なことですが、上記の操作は著しく複雑になります。合理的な約束の実装はそうです。

  4. さまざまなタイプの「解決」操作が必要です。「解決」(基本アクションが成功) と「拒否」(失敗) です。いくつかのユースケースにはさらに多くの状態があるかもしれませんが、解決済みと拒否は基本的な 2 つです。(ES2015 の約束には解決と拒否があります。)

  5. promise の作成者だけがそれを解決できるように、何らかの方法でsettle(または別のresolveand を) 非公開にすることができます。reject(ES2015 の約束 — およびその他のいくつか — は、パラメーター値としておよびPromiseを受け取るコールバックをコンストラクターに受け入れるようにすることでこれを行います。したがって、そのコールバック内のコードのみが解決または拒否できます [コールバック内のコードが何らかの方法でそれらを公開しない限り]。)resolvereject

などなど

于 2013-03-27T19:55:44.247 に答える
15

誰かが数行で最も基本的な約束を実装できますか?

ここにあります:

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

チェーン付きの追加(答えthenに必要です):

Promise.prototype.then = function(fn) {
    return new Promise(fulfill => {
        this.addCallback((...args) => {
            const result = fn(...args);
            if (result instanceof Promise)
                result.addCallback(fulfill);
            else
                fulfill(result);
        });
    });
};

これら 2 つのスニペットはどのように関連していますか?

ajax関数から呼び出されgetPromiseForAjaxResultます:

function getPromiseForAjaxResult(ressource) {
    return new Promise(function(callback) {
        ajax({url:ressource}, callback);
    });
}
于 2013-03-27T20:04:13.043 に答える