worker で then に console.log を渡すと謎の出力が増える
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ 2 回ログが表示される
◆ 2 回目は文字列化されたもの
◆ 1 秒以内だけど少し遅延してから 2 回目が表示されてる
◆ ワーカー内かつ then/catch に console.log を渡す使い方でだけ発生
◆ 2 回目は文字列化されたもの
◆ 1 秒以内だけど少し遅延してから 2 回目が表示されてる
◆ ワーカー内かつ then/catch に console.log を渡す使い方でだけ発生
謎の現象
worker で console.log を使うとなぜか 2 重に出力されます<!doctype html>
<script>
const str = `
console.log(1)
Promise.resolve(2).then(console.log)
`
const file = URL.createObjectURL(new Blob([str]))
console.log(0)
new Worker(file)
</script>
このコードを実行します
str の文字列がワーカーコンテキストで実行されるコードです
コンソールに出力される 期待する内容はこれです
0
1
2
まずはページ側で 0 が出力され 次にワーカーの console.log で 1 最後に Promise の then から 2 です
なのに実際に表示されるのは
0
1
2
2
です
2 が 2 回表示されます
しかも 色も違って最後の 2 だけ白色です
文字列としての出力になってそうです
試しにワーカーの処理をこう変更してみます
console.log(1)
Promise.resolve(2).then(console.log)
Promise.resolve({}).then(console.log)
すると
0
1
2
2
{}
[object Object]
オブジェクトが文字列化されています
発生条件
これが起きるのはワーカーの中でだけです普通のページで
Promise.resolve(2).then(console.log)
を実行しても 2 が 1 回表示されるだけです
無いとは思うのですが ワーカーだと then で受け取るものが違うのかなと思って関数を通してみました
Promise.resolve(2).then((...a) => console.log(...a))
こうすると発生せず 1 回だけの出力になります
直接 then に console.log を渡す場合だけみたいです
また この現象は他の console メソッドにしたり then を catch にしても起きます
Promise.reject(2).catch(console.error)
Promise.resolve だからに限らず
fetch("/").then(console.log)
new Promise(r => setTimeout(r, 1000, 2)).then(console.log)
などでも起きます
今の console.log は log が呼びされるときの this コンテキストに依存しないはずですが 他に違いといえばこれくらいです
Promise.resolve(2).then(function() {
console.log(this === globalThis)
// true
})
これで true になることを確認してから
const log = console.log
log.call(globalThis, 2)
を試してみました
しかし これも問題なしです
バグ?
ワーカーで cosnole.log を呼び出せば確実に発生 ならともかく then に直接渡したときだけですまた なぜか文字列化されます
devtools 上の 呼び出し元のソースコードへのリンクは壊れています
さらに 連続して表示されるとき 同時ではなく文字列化された方は 0.5 秒ほど遅れて表示されます
もうバグにしかみえないのですけどちゃんとした理由があるのでしょうか