TL & DR:私たちはキャンセル可能な約束をここに発明しています。
まあいいです。インフラストラクチャこれはあなたが本当に必要とする典型的な例ですPromise.cancel()
しかし、私たちはES6ネイティブ約束にそれを持っていません。図書館に頼らない人であることから、私はプロミスのサブクラス化によって進化していきます。
次の関数は、約束を取り、それはまたそれに.then()
と.cancel()
メソッドを追加__cancelled__
と呼ばれる非可算・非設定可能なプロパティを追加することによって、それが解約になりPromise.prototype
を変更することなく、プロパティチェーンです。キャンセル可能な約束オブジェクトのプロトタイプのプロトタイプはPromise.prototype
であるため、キャンセル可能な約束はすべての約束事にアクセスできます。ああ、忘れる前に。キャンセル可能なプロトタイプのthen
メソッドもキャンセル可能な約束を返します。
function makePromiseCancellable(p){
Object.defineProperty(p,"__cancelled__", { value: false,
writable: true,
enumerable: false,
configurable: false
});
Object.setPrototypeOf(p,makePromiseCancellable.prototype);
return p;
}
makePromiseCancellable.prototype = Object.create(Promise.prototype);
makePromiseCancellable.prototype.then = function(callback){
return makePromiseCancellable(Promise.prototype.then.call(this,function(v){
!this.__cancelled__ && callback(v);
}.bind(this)));
};
makePromiseCancellable.prototype.cancel = function(){
this.__cancelled__ = true;
return this;
};
だから私たちは私たちに2000ミリ秒で解決標準ES6の約束を返すgetAsyncData()
というユーティリティ機能を持っています。この関数から2つの約束を得て、cp0
とcp1
という取り消し可能約束に変えます。次に、cp0
を1000ミリ秒でキャンセルし、何が起こるかを確認します。
function getAsyncData(){
var dur = 2000;
return new Promise((v,x) => setTimeout(v.bind(this,"promise id " + pid++ + " resolved at " + dur + " msec"),dur));
}
function makePromiseCancellable(p){
Object.defineProperty(p,"__cancelled__", { value: false,
writable: true,
enumerable: false,
configurable: false
});
Object.setPrototypeOf(p,makePromiseCancellable.prototype);
return p;
}
makePromiseCancellable.prototype = Object.create(Promise.prototype);
makePromiseCancellable.prototype.then = function(callback){
return makePromiseCancellable(Promise.prototype.then.call(this,function(v){
!this.__cancelled__ && callback(v);
}.bind(this)));
};
makePromiseCancellable.prototype.cancel = function(){
this.__cancelled__ = true;
};
var pid = 0,
cp0 = makePromiseCancellable(getAsyncData());
cp1 = makePromiseCancellable(getAsyncData());
cp0.then(v => console.log(v));
cp1.then(v => console.log(v));
setTimeout(_ => cp0.cancel(),1000);
うわー...!素晴らしい。が2000ミリ秒で解決され、cp0
が1000ミリ秒でキャンセルされた。
インフラストラクチャが完成しましたので、これを使用して問題を解決できます。
以下は、私たちが使用するコードです。
function getAsyncData(){
var dur = ~~(Math.random()*9000+1001);
return new Promise((v,x) => setTimeout(v.bind(this,"promise id " + pid++ + " resolved at " + dur + " msec"),dur));
}
function runner(fun,cb){
var promises = [];
return setInterval(_ => { var prom = makePromiseCancellable(fun());
promises.push(prom);
promises[promises.length-1].then(data => { promises.forEach(p => p.cancel());
promises.length = 0;
return cb(data);
});
},1000);
}
var pid = 0,
sid = runner(getAsyncData,v => console.log("received data:", v));
setTimeout(_=> clearInterval(sid),60001);
かなり基本的です。 runner()
機能が機能しています。それはgetAsyncData()
を呼び出すことによって1000msecごとに約束を要求しています。しかし、今度はgetAsyncData()
の機能は、1〜10秒で解決できる約束を与えるでしょう。これは、後で約束されたものの一部が以前に受け取ったものの未解決の状態にある間に解決できるようにするためです。あなたの場合のように。 OK;受け取った約束を取り消し可能にした後、runner()
関数はそれをpromises
配列にプッシュします。約束をpromises
配列にプッシュした後でなければ、then
ステージから返されたものではなく、主な約束だけを配列に保持したいので、then命令をその配列に追加します。今まで約束していたもののどれかがthen
メソッドと呼ばれていた場合、まず配列内のすべての約束をキャンセルしてから配列を空にします。それ以降は、指定されたコールバック関数が呼び出されます。
ここで、すべての動作を見てみましょう。
function makePromiseCancellable(p){
Object.defineProperty(p,"__cancelled__", { value: false,
writable: true,
enumerable: false,
configurable: false
});
Object.setPrototypeOf(p,makePromiseCancellable.prototype);
return p;
}
makePromiseCancellable.prototype = Object.create(Promise.prototype);
makePromiseCancellable.prototype.then = function(callback){
return makePromiseCancellable(Promise.prototype.then.call(this,function(v){
!this.__cancelled__ && callback(v);
}.bind(this)));
};
makePromiseCancellable.prototype.cancel = function(){
this.__cancelled__ = true;
return this;
};
function getAsyncData(){
var dur = ~~(Math.random()*9000+1001);
return new Promise((v,x) => setTimeout(v.bind(this,"promise id " + pid++ + " resolved at " + dur + " msec"),dur));
}
function runner(fun,cb){
var promises = [];
return setInterval(_ => { var prom = makePromiseCancellable(fun());
promises.push(prom);
promises[promises.length-1].then(data => { promises.forEach(p => p.cancel());
promises.length = 0;
return cb(data);
});
},1000);
}
var pid = 0,
sid = runner(getAsyncData,v => console.log("received data:", v));
setTimeout(_=> clearInterval(sid),60001);
あなたはそれを停止しない場合runner
機能がindefinitelly実行されます。だから60001msecsで私はclearInterval()
でそれをクリアします。その期間に約60件の約束が受理され、promises
配列で最初に解決された約束の後に受け取った未解決のものを含めて、の前にのすべての約束を取り消すことによって、しかし、後の約束はより新鮮なデータを含むことが予想されるので、それらを解読しないようにしたいかもしれない。次に、コードの次の小さな変更が、最新のデータで頻繁に画面をリフレッシュするという点でより良い結果をもたらすと考えています。もちろん、いくつかの欠点があるかもしれません
function makePromiseCancellable(p){
Object.defineProperty(p,"__cancelled__", { value: false,
writable: true,
enumerable: false,
configurable: false
});
Object.setPrototypeOf(p,makePromiseCancellable.prototype);
return p;
}
makePromiseCancellable.prototype = Object.create(Promise.prototype);
makePromiseCancellable.prototype.then = function(callback){
return makePromiseCancellable(Promise.prototype.then.call(this,function(v){
!this.__cancelled__ && callback(v);
}.bind(this)));
};
makePromiseCancellable.prototype.cancel = function(){
this.__cancelled__ = true;
return this;
};
function getAsyncData(){
var dur = ~~(Math.random()*9000+1001);
return new Promise((v,x) => setTimeout(v.bind(this,"promise id " + pid++ + " resolved at " + dur + " msec"),dur));
}
function runner(fun,cb){
var promises = [];
return setInterval(_ => { var prom = makePromiseCancellable(fun());
promises.push(prom);
promises[promises.length-1].then(data => { var prix = promises.indexOf(prom);
promises.splice(0,prix)
.forEach(p => p.cancel());
return cb(data);
});
},1000);
}
var pid = 0,
sid = runner(getAsyncData,v => console.log("received data:", v));
setTimeout(_=> clearInterval(sid),60001);
。私はあなたのアイデアを聞きたい。
リクエストが完了した順序を決めることは決してできません(実際にサーバー側で実装するのは当然です)。タイムスタンプの考え方がおそらく最良の解決策です。 – Cine
レスポンスタイムスタンプが役立つかどうかわからない...あなたの例では、タイムスタンプが応答にいつ追加されるかに応じて、最初のリクエストで後のタイムスタンプを取得しないでしょうか?またはタイムスタンプはリクエストの時刻です –
@ JaromandaXありがとう、私はそれに気づいていなかった...しかし、私は後で要求が実際に新しい情報を取得することをテストした後、要求時間を代わりに使用することができます:S –