[解決済み] setTimeoutからプロミスを作成する方法
質問
これは現実の問題ではなく、約束がどのように作成されるかを理解しようとしているだけです。
setTimeoutのような何も返さない関数に対して、どのようにプロミスを作るかを理解する必要があります。
私が持っているとします。
function async(callback){
setTimeout(function(){
callback();
}, 5000);
}
async(function(){
console.log('async called back');
});
どのようにすれば
async
の後に返すことができます。
setTimeout
の準備ができたら
callback()
?
包むとどこかに行けると思ったのですが。
function setTimeoutReturnPromise(){
function promise(){}
promise.prototype.then = function() {
console.log('timed out');
};
setTimeout(function(){
return ???
},2000);
return promise;
}
しかし、この先が思いやられます。
どうすればいいのでしょうか?
アップデート(2017年)
2017年、プロミスはJavaScriptに組み込まれ、ES2015仕様で追加されました(IE8-IE11などの古い環境ではポリフィルが利用可能です)。プロミスの構文は
Promise
コンストラクタに渡すコールバックを使用します (この
Promise
エグゼキュータ
) で、プロミスを解決/拒否するための関数を引数として受け取ります。
まず
async
がJavaScriptで意味を持つようになったので
を使うようになったので (特定のコンテキストでのキーワードに過ぎないにもかかわらず)
later
を関数の名前として使うことにします。
基本的な遅延
ネイティブプロミス(または忠実なポリフィル)を使用すると、次のようになります。
function later(delay) {
return new Promise(function(resolve) {
setTimeout(resolve, delay);
});
}
のバージョンを仮定していることに注意してください。
setTimeout
に準拠した
ブラウザのための定義
ここで
setTimeout
は、間隔の後に引数を与えない限り、コールバックに引数を渡しません (これは非ブラウザ環境では真ではないかもしれませんし、以前は Firefox では真ではありませんでしたが、現在は真です。Chrome でもそうですし、IE8 でも戻っています)。
値による基本的な遅延
関数にオプションで解決値を渡したい場合、漠然とした近代的なブラウザで
setTimeout
に追加引数を与えることができ、呼び出されたときにそれらをコールバックに渡すことができる、漠然とした最新のブラウザでは、これを行うことができます (現在の Firefox と Chrome。IE11+、おそらく Edge。
ではなく
IE8 または IE9、IE10 については不明)。
function later(delay, value) {
return new Promise(function(resolve) {
setTimeout(resolve, delay, value); // Note the order, `delay` before `value`
/* Or for outdated browsers that don't support doing that:
setTimeout(function() {
resolve(value);
}, delay);
Or alternately:
setTimeout(resolve.bind(null, value), delay);
*/
});
}
ES2015+の矢印関数を使っている場合は、より簡潔な表現になります。
function later(delay, value) {
return new Promise(resolve => setTimeout(resolve, delay, value));
}
あるいは
const later = (delay, value) =>
new Promise(resolve => setTimeout(resolve, delay, value));
値によるキャンセル可能な遅延
タイムアウトをキャンセルできるようにする場合、プロミスを返すのは
later
を返すことはできません。なぜなら、プロミスはキャンセルできないからです。
しかし、私たちは簡単にオブジェクトを返すために
cancel
メソッドとプロミスへのアクセサを持つオブジェクトを返し、キャンセル時にプロミスを拒否することができます。
const later = (delay, value) => {
let timer = 0;
let reject = null;
const promise = new Promise((resolve, _reject) => {
reject = _reject;
timer = setTimeout(resolve, delay, value);
});
return {
get promise() { return promise; },
cancel() {
if (timer) {
clearTimeout(timer);
timer = 0;
reject();
reject = null;
}
}
};
};
ライブの例です。
const later = (delay, value) => {
let timer = 0;
let reject = null;
const promise = new Promise((resolve, _reject) => {
reject = _reject;
timer = setTimeout(resolve, delay, value);
});
return {
get promise() { return promise; },
cancel() {
if (timer) {
clearTimeout(timer);
timer = 0;
reject();
reject = null;
}
}
};
};
const l1 = later(100, "l1");
l1.promise
.then(msg => { console.log(msg); })
.catch(() => { console.log("l1 cancelled"); });
const l2 = later(200, "l2");
l2.promise
.then(msg => { console.log(msg); })
.catch(() => { console.log("l2 cancelled"); });
setTimeout(() => {
l2.cancel();
}, 150);
2014年のオリジナル回答
通常、プロミスライブラリ(自分で書いたもの、または世の中にあるいくつかのうちの1つ)を持っていると思います。そのライブラリは通常、あなたが作成し、後で "解決することができるオブジェクトを持っており、そのオブジェクトはあなたがそこから取得できる "約束"を持っています。
次に
later
はこのような感じになりがちです。
function later() {
var p = new PromiseThingy();
setTimeout(function() {
p.resolve();
}, 2000);
return p.promise(); // Note we're not returning `p` directly
}
質問のコメントで、「?
独自のプロミスライブラリを作ろうとしているのでしょうか?
とのことですが、あなたは
<ブロッククオート私はそうではありませんでしたが、私が理解しようとしていたのは、実はこれだったのだと思います。ライブラリがどのようにそれを行うか
その理解を助けるために、ここで 非常に基本的な の例です。これは Promises-A には全く準拠していません。 ライブコピー
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Very basic promises</title>
</head>
<body>
<script>
(function() {
// ==== Very basic promise implementation, not remotely Promises-A compliant, just a very basic example
var PromiseThingy = (function() {
// Internal - trigger a callback
function triggerCallback(callback, promise) {
try {
callback(promise.resolvedValue);
}
catch (e) {
}
}
// The internal promise constructor, we don't share this
function Promise() {
this.callbacks = [];
}
// Register a 'then' callback
Promise.prototype.then = function(callback) {
var thispromise = this;
if (!this.resolved) {
// Not resolved yet, remember the callback
this.callbacks.push(callback);
}
else {
// Resolved; trigger callback right away, but always async
setTimeout(function() {
triggerCallback(callback, thispromise);
}, 0);
}
return this;
};
// Our public constructor for PromiseThingys
function PromiseThingy() {
this.p = new Promise();
}
// Resolve our underlying promise
PromiseThingy.prototype.resolve = function(value) {
var n;
if (!this.p.resolved) {
this.p.resolved = true;
this.p.resolvedValue = value;
for (n = 0; n < this.p.callbacks.length; ++n) {
triggerCallback(this.p.callbacks[n], this.p);
}
}
};
// Get our underlying promise
PromiseThingy.prototype.promise = function() {
return this.p;
};
// Export public
return PromiseThingy;
})();
// ==== Using it
function later() {
var p = new PromiseThingy();
setTimeout(function() {
p.resolve();
}, 2000);
return p.promise(); // Note we're not returning `p` directly
}
display("Start " + Date.now());
later().then(function() {
display("Done1 " + Date.now());
}).then(function() {
display("Done2 " + Date.now());
});
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
})();
</script>
</body>
</html>
関連
-
[解決済み] 配列から特定の項目を削除するにはどうすればよいですか?
-
[解決済み] jQueryで要素が非表示になっているかどうかを確認するには?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptでタイムスタンプを取得する方法は?
-
[解決済み】別のウェブページにリダイレクトするにはどうすればいいですか?
-
[解決済み】オブジェクトからプロパティを削除する(JavaScript)
-
[解決済み] モバイルWeb HTML5フレームワークの選び方【終了しました
-
[解決済み] V8 Javascript エンジンのスタンドアロン実行
-
[解決済み] マングース ユーザーの全リストを取得する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] JSのDateからDay名
-
[解決済み] Angularjs - 現在の日付を表示する
-
[解決済み] $.ajax実行中にローディングイメージを表示する
-
[解決済み] JavaScriptで長い配列を小さい配列に分割する方法
-
[解決済み] JavaScript で `throw` の後に `return` をする必要がありますか?
-
[解決済み] JavaScriptのArray.sort()メソッドでシャッフルするのは正しいのか?
-
[解決済み] WebpackでjQueryを本物のWindowオブジェクトに公開する
-
[解決済み] マングース ユーザーの全リストを取得する
-
[解決済み] Bootstrap モーダル:トグル時に背景がトップにジャンプする
-
[解決済み] node.js シェルコマンドの実行