2017-02-09 5 views
0

次のjavascriptコードには未定義の動作がありますか?

var resolve; 
 

 
var head = { next: new Promise(r => resolve = r) }; 
 

 
function addData(d) { 
 
    resolve({ 
 
     data: d, 
 
     next: new Promise(r => resolve = r) 
 
    }); 
 
}

リスト内のデータを非同期的にロードされている間、私は、リンクリストのようなものを達成するために上記のコードを書きました。

このリンク済みリストの先頭はheadです。リスト内の各ノードには、通常のリンクリストのように、.data.nextの2つのフィールドがあります。 .nextは、リストの次のノードに解決される約束です。

毎回addData(...)が呼び出されると、リストの現在の最後のノードの.nextフィールドが新しいノードに解決され、新しい最後のノードになります。

上記のコードの機能をNode.jsで確認したところ、期待通りに機能しています。ここで私は動作を確認するために使用するコードは次のとおりです。

var resolve; 
 
var head = { next: new Promise(r => resolve = r) }; 
 
function addData(d) { resolve({ data: d, next: new Promise(r => resolve = r) }); } 
 

 
async function verify() { 
 
    while(true) { 
 
     head = await head.next; 
 
     console.log(head.data); 
 
    } 
 
} 
 

 
verify(); 
 
addData(1); // outputs: 1 
 
addData(2); // outputs: 2 
 
addData(3); // outputs: 3

しかし、私はこのような構造を持つ任意の潜在的な問題(メモリ、効率)があるかどうかわかりません。決意が同時に呼び出され、割り当てられている

resolve({data: d, next: new Promise(r => resolve = r})

:また、私はこのラインについては特に心配です。まず、代入や関数の名前解決が起こるはずですか?これは未定義の動作ですか?

ありがとうございました!

+1

それが動作しているかどうかに関わらず、それは確かに鈍い(コードの読み方と理解が難しい)。 – jfriend00

+0

@ jfriend00彼は最初の頭を参照していればチェーン全体を保持しています。もちろん、間違ってしまうのは簡単です... – Bergi

+0

@Bergi - 私はこれが何が起こっているのか分かりにくいと結論付けているので、そのコメントを削除しました。しかし、OPは「リンクされたリストのように」言っていましたが、リンクされたリストではないと思います。私はそれが前の約束のより高いスコープのキャッシュだと思う。これを行うもっと良い方法はありませんが、これはあまり鈍くなく、より高いスコープの 'resolve'変数を使用しませんか? – jfriend00

答えて

0

どのようなことが最初に起こるべきでしょうか?

関数名前解決は(順番に割り当てを含むコールバックを呼び出すPromiseコンストラクタコールを含むリテラルオブジェクト)引数の評価の前に起こります。

これは未定義の動作ですか?

いいえ、コードの匂いです。

これを行うにはどのように優雅な方法がありますか?

はい。これは主にデータ構造の生成方法に依存します。あなたが他の誰かがデータを生成不可欠なアプローチを使用している場合は、私は非同期キューリストを呼び出し、中に入れたい

function getStream(i) { 
    return new Promise(resolve => { 
     setTimeout(resolve, 100); 
    }).then(() => ({ 
     data: i, 
     next: getStream(i+1) 
    })); 
} 
(async function() { 
    for (var data, next, head = getStream(1); {data, next} = await head; head = next) { 
     console.log(data); 
    } 
}()); 

:あなたは、機能的なアプローチを使用している場合、私は、再帰関数をお勧めします適切な構造ですが、addDataコードは問題ありません(余分な変数で管理できるresolveに関する混乱を除いて)。

+0

答えをありがとう!この "リンクリスト"構造を実装する必要がある場合は、これを行うためのより良い/エレガントな方法がありますか? –

0

Bergiが指摘するように、これは未定義の動作ではありませんが、これを実装する方法は紛らわしいものではありません。それはresolve機能を割り当て、同じ文の中でそれを呼び出すしないように

たとえば、あなたはaddData関数を書くことができます:あなたは非常に遠回りなアプローチへを使用している場合がありますように

function addData(d) { 
    let newResolve; 

    resolve({ data: d, next: new Promise(r => newResolve = r) }); 

    resolve = newResolve; 
} 

に見えますストリームまたは観測可能なコレクションを作成することができます。その場合は、それらの既存の実装を使用する方がよい場合があります。

+0

'resolve'関数を格納するよりも遅延を保存する方がいいですか? – Bergi

+0

@Bergi私は少しはっきりしているようですが、公正な点です。私は同じステートメントで 'resolve 'を呼び出して割り当てる混乱する行を避けるために私の答えを変更しました。 – JLRishe

+0

お返事ありがとうございました!アプリケーションは、実際にはいくつかの言葉で説明するために複雑です。私は要件に適合するいくつかの既存の実装を見つけることを試みるでしょう.... –

関連する問題