首頁 > web前端 > js教程 > JavaScript中的多線程

JavaScript中的多線程

Christopher Nolan
發布: 2025-02-25 11:37:12
原創
885 人瀏覽過

JavaScript中的多線程

好吧,在我們開始之前,讓我清理並承認本文的標題有點聳人聽聞! JavaScript實際上沒有多線程功能,JavaScript程序員無能為力。在所有瀏覽器中 - 除了Google Chrome - JavaScript都以單個執行線程運行,這就是它的方式。

> 但是,我們能做的是模擬

多線程,這在多線程環境中帶來了一個好處之一:它允許我們運行極其密集的代碼。這是代碼,否則將凍結瀏覽器並在Firefox中生成其中一個“反應式腳本”警告。 > 鑰匙要點

JavaScript

>不本質地支持多線程,而是通過異步計時器和網絡工作人員進行模擬,允許密集的計算而無需冷凍瀏覽器。
    >異步計時器將任務分解為較小的塊,從而通過管理代碼如何隨著時間的推移來執行方式來防止瀏覽器變得無響應。
  • >
  • > Web工作者增強了JavaScript執行背景任務而不會影響用戶界面的能力,儘管他們無法與DOM進行交互或使用某些Web API。
  • 對於冒著鎖定瀏覽器的複雜操作,使用異步計時器進行重構代碼可以防止UI凍結並更有效地管理資源密集型過程。
  • 儘管JavaScript具有單線程的性質,但諸如異步編程和網絡工作人員之類的技術為開發人員提供了強大的工具來處理多線程式的方案,從而提高了強化任務的性能。
  • 時間等待沒有一個人
  • >這一切都取決於使用異步計時器的使用。當我們在異步計時器中運行重複代碼時,我們將為瀏覽器的腳本解釋器處理每次迭代的時間。
  • > 有效地,迭代器中的一塊代碼正在要求解釋器立即完成所有操作:“運行此代碼 n
  • 盡可能快地運行。”但是,異步計時器內的相同代碼將代碼分解成小謹慎的塊。也就是說,“運行此代碼一次盡可能快”,然後等待 - 然後“盡可能快地運行此代碼”,依此類推,
訣竅是,每次迭代內部的代碼都很小且簡單,以使解釋器在計時器速度(無論是100或5,000毫秒)的速度以內處理。如果滿足了該要求,那麼整體代碼的強度都沒有關係,因為我們並不要求一次運行它。

>

“太激烈”多麼激烈?
> 通常,如果我編寫一個被證明太密集的腳本,我會考慮重新設計它;這樣的顯著放緩通常表明代碼存在問題,或者是應用程序設計的更深層次問題。

,但有時不是。有時根本無法避免特定操作的強度,而根本沒有在JavaScript中進行。 在給定情況下,這可能是最好的解決方案;也許在應用程序中的某些處理需要移至服務器端,在該服務器端,它具有更多的處理能力,通常可以使用,以及真正的線程執行環境(Web服務器)。

>但最終您可能會發現這不是一個選擇的情況 - JavaScript簡單地

必須

能夠做某事或該死。這就是我在開發Firefox擴展時發現自己的情況。 該擴展名的核心是測試適用於頁面的CSS選擇器的能力,以查看是否實際使用它們。此的本質是使用Dean Edwards'Base2:的Matchall()方法的一組評估

>肯定足夠直接。但是agetall()本身非常強烈,就像它一樣- 要解析和評估任何CSS1或CSS2選擇器,然後走整個DOM樹尋找匹配;並且擴展程序是為的每個單獨的選擇器的,其中可能有幾千個。表面上如此簡單,該過程可能是如此密集,以至於整個瀏覽器發生在發生時。這就是我們發現的。

鎖定瀏覽器顯然不是一個選項,因此,如果這根本無法使用,我們必須找到一種使它運行而不會出錯的方法。

>

一個簡單的測試用例
for(var i=0; i<selectors.length; i++) <br>
{ <br>
  if(base2.DOM.Document.matchAll <br>
    (contentdoc, selectors[i]).length > 0) <br>
  { <br>
    used ++; <br>
  } <br>
  else <br>
  { <br>
    unused ++; <br>
  } <br>
}
登入後複製
登入後複製
登入後複製
登入後複製

>讓我們通過一個簡單的測試案例來證明問題,涉及兩個迭代級別;內部層面故意太密集,因此我們可以創建比賽條件,而外部層面相當短,因此它可以模擬主代碼。這就是我們所擁有的:

>我們從簡單的表單(這是測試代碼,而不是生產)開始測試,並獲取輸出

現在,讓我們在Firefox中運行該代碼(在這種情況下,在2GHz MacBook上使用Firefox 3)……並且正如預期的那樣,瀏覽器UI在運行時凍結(例如,不可能,例如不可能按刷新並放棄該過程) 。大約90次迭代後,Firefox產生了一個“反應式腳本”警告對話框。

function process() <br>
{ <br>
  var above = 0, below = 0; <br>
  for(var i=0; i<200000; i++) <br>
  { <br>
    if(Math.random() * 2 > 1) <br>
    { <br>
      above ++;       <br>
    } <br>
    else <br>
    { <br>
      below ++; <br>
    } <br>
  } <br>
} <br>
 <br>
 <br>
function test1() <br>
{ <br>
  var result1 = document.getElementById('result1'); <br>
   <br>
  var start = new Date().getTime(); <br>
     <br>
  for(var i=0; i<200; i++) <br>
  { <br>
    result1.value =  'time=' +  <br>
      (new Date().getTime() - start) + ' [i=' + i + ']'; <br>
     <br>
    process(); <br>
  } <br>
   <br>
  result1.value = 'time=' +  <br>
    (new Date().getTime() - start) + ' [done]'; <br>
}
登入後複製
登入後複製
登入後複製
如果我們允許它繼續下去,在另外90個迭代後,Firefox再次產生相同的對話框。在這方面,Safari 3和Internet Explorer 6的行為類似,並具有凍結的UI和一個警告對話框的閾值。在Opera中沒有這樣的對話框 - 它只是繼續運行代碼直到完成代碼 - 但是瀏覽器UI類似地凍結了直到完成任務。

顯然,在實踐中我們無法運行代碼。因此,讓我們重新開始並使用異步計時器進行外循環:>

>現在讓我們再次運行……這一次我們會收到完全不同的結果。該代碼需要一段時間才能完成,但是它可以一直成功地運行到末端,而沒有UI凍結,並且沒有警告過度緩慢的腳本。

for(var i=0; i<selectors.length; i++) <br>
{ <br>
  if(base2.DOM.Document.matchAll <br>
    (contentdoc, selectors[i]).length > 0) <br>
  { <br>
    used ++; <br>
  } <br>
  else <br>
  { <br>
    unused ++; <br>
  } <br>
}
登入後複製
登入後複製
登入後複製
登入後複製
>查看測試頁面

(繁忙的標誌用於防止計時器實例發生碰撞。如果我們已經在下一次迭代時已經處於子過程中的中間,我們只需等待以下迭代,從而確保只有一個子過程一次運行。)

>因此,您可以看到,儘管我們可以在

> Inner

過程中所做的工作仍然很小,但

的次數>我們可以運行該過程是無限的:我們可以運行該過程外循環基本上永遠是永遠的,瀏覽器將永遠不會凍結。 >更喜歡它 - 我們可以在野外使用它。 你瘋了!

>我已經可以聽到反對者了。實際上,我可能自己是一個人:您為什麼要這樣做 - 什麼樣的瘋子堅持將JavaScript推到從未被設計為去的所有這些地方?您的代碼太強烈了。這是工作的錯誤工具。如果您必須跳過這類箍,那麼您的應用程序的設計從根本上是錯誤的。

>我已經提到了一個例子,我必須找到一種繁重的腳本工作的方法。就是這樣,或者整個想法必須放棄。如果您不相信該答案,那麼本文的其餘部分也可能對您不吸引您。

>但是,如果您是 - 或者至少,如果您願意說服它,這是另一個真正可以將其釘在家裡的示例:使用JavaScript編寫可以在計算機上進行比賽的遊戲。 >>>>>

>上的遊戲

我在這裡說的是了解遊戲規則所需的代碼,然後可以評估情況和策略,以便在該遊戲中擊敗您。複雜的東西。

為了說明,我要看一個我在一邊開發的項目一段時間。 “小時”是指三年

,其中大多數是在理論上工作的高原上花費的,但太強烈了,無法使用……直到我想到了這種方法。該遊戲是一個基於顏色和形狀匹配的競爭難題。

>

JavaScript中的多線程

總結一下:您通過相鄰的形狀和顏色匹配來整個過程。例如,如果您開始使用綠色三角形 - 那麼您可以移至任何其他三角形或任何其他綠色形狀。您的目標是到達中間的水晶,然後將其帶到板的另一側,而對手則嘗試這樣做。您也可以從對手那裡竊取水晶。

因此,我們有確定運動的邏輯規則,我們還可以看到策略的出現。例如,為了避免讓對手到達水晶,或從您那裡偷走它 - 您可能會選擇阻止它們的動作,或者嘗試在他們無法到達的地方完成。

計算機的工作是在任何給定的情況下找到最佳的動作,因此讓我們查看摘要偽代碼中的該過程:

>

for(var i=0; i<selectors.length; i++) <br>
{ <br>
  if(base2.DOM.Document.matchAll <br>
    (contentdoc, selectors[i]).length > 0) <br>
  { <br>
    used ++; <br>
  } <br>
  else <br>
  { <br>
    unused ++; <br>
  } <br>
}
登入後複製
登入後複製
登入後複製
登入後複製
我們評估了一種策略,如果這給了我們一個好的舉動,那麼我們就完成了;否則,我們將評估另一種策略,依此類推,直到我們有動作,或者得出結論,我們必須通過。

>每個策略功能都運行一個昂貴的過程,因為它必須評估董事會中的每個職位以及潛在的未來位置,可能會根據各種因素進行多次。該示例只有三種策略,但是在真實的遊戲中,有數十種可能性,每個可能性都昂貴。

>

>單獨評估中的任何一個都很好,但是所有這些評估都可以連續運行,使過度激烈的過程凍結了瀏覽器。

>

>因此,我所做的是將主代碼拆分為“謹慎”任務

,每個任務都是用開關語句選擇的,然後使用異步計時器進行迭代。這樣做的邏輯距離那些小時候的那些選擇您曾經有過的冒險書的邏輯不到一百萬英里,在那裡,每個任務都以實時的選擇結束,直到我們到達終點:>

此代碼比原始代碼明顯高得多,因此,如果減少代碼大小是唯一的命令,這顯然不是要走的路。

但是,我們在這裡要做的是創建一個沒有天花板的執行環境,即,在復雜性和長度方面沒有上限的過程;這就是我們所做的。
function process() <br>
{ <br>
  var above = 0, below = 0; <br>
  for(var i=0; i<200000; i++) <br>
  { <br>
    if(Math.random() * 2 > 1) <br>
    { <br>
      above ++;       <br>
    } <br>
    else <br>
    { <br>
      below ++; <br>
    } <br>
  } <br>
} <br>
 <br>
 <br>
function test1() <br>
{ <br>
  var result1 = document.getElementById('result1'); <br>
   <br>
  var start = new Date().getTime(); <br>
     <br>
  for(var i=0; i<200; i++) <br>
  { <br>
    result1.value =  'time=' +  <br>
      (new Date().getTime() - start) + ' [i=' + i + ']'; <br>
     <br>
    process(); <br>
  } <br>
   <br>
  result1.value = 'time=' +  <br>
    (new Date().getTime() - start) + ' [done]'; <br>
}
登入後複製
登入後複製
登入後複製

這個模式可以無限期地擴展

,具有數百甚至數千個任務。它可能需要很長時間才能運行,但是將其運行,並且只要每個

個體

任務都不太強烈,它將在不殺死瀏覽器的情況下運行。 >

無返回的路徑 這種方法的強度也是它的主要弱點:由於內部函數是異步的,因此我們無法從外部函數中返回值。因此,例如,我們無法做到這一點(或者,我們可以,但沒有意義):>

for(var i=0; i<selectors.length; i++) <br>
{ <br>
  if(base2.DOM.Document.matchAll <br>
    (contentdoc, selectors[i]).length > 0) <br>
  { <br>
    used ++; <br>
  } <br>
  else <br>
  { <br>
    unused ++; <br>
  } <br>
}
登入後複製
登入後複製
登入後複製
登入後複製

checksomething()函數將始終始終返回false,因為內部函數是異步的。外部功能將在內部功能的第一次迭代發生之前返回!

下一個示例同樣毫無意義:

function process() <br>
{ <br>
  var above = 0, below = 0; <br>
  for(var i=0; i<200000; i++) <br>
  { <br>
    if(Math.random() * 2 > 1) <br>
    { <br>
      above ++;       <br>
    } <br>
    else <br>
    { <br>
      below ++; <br>
    } <br>
  } <br>
} <br>
 <br>
 <br>
function test1() <br>
{ <br>
  var result1 = document.getElementById('result1'); <br>
   <br>
  var start = new Date().getTime(); <br>
     <br>
  for(var i=0; i<200; i++) <br>
  { <br>
    result1.value =  'time=' +  <br>
      (new Date().getTime() - start) + ' [i=' + i + ']'; <br>
     <br>
    process(); <br>
  } <br>
   <br>
  result1.value = 'time=' +  <br>
    (new Date().getTime() - start) + ' [done]'; <br>
}
登入後複製
登入後複製
登入後複製

>我們不超出外部功能的範圍,因此我們無法從中返回;該返回值無用地消失在以太中。

我們的> 在這裡做的是從AJAX編碼技術中取出葉子,並使用回調函數(在此示例中,我稱為“ oncomplete”):

>
<form action=""> <br>
  <fieldset> <br>
    <input type="button" value="test1" onclick="test1()" /> <br>
    <input type="text"  /> <br>
  </fieldset> <br>
</form> <br>
登入後複製

因此,當我們調用checkSomething()時,我們將匿名函數作為其參數,並且當作業完成時,該函數以最終值調用:

>
function test2() <br>
{ <br>
  var result2 = document.getElementById('result2'); <br>
   <br>
  var start = new Date().getTime(); <br>
   <br>
  var i = 0, limit = 200, busy = false; <br>
  var processor = setInterval(function() <br>
  { <br>
    if(!busy) <br>
    { <br>
      busy = true; <br>
       <br>
      result2.value =  'time=' +  <br>
        (new Date().getTime() - start) + ' [i=' + i + ']'; <br>
       <br>
      process(); <br>
       <br>
      if(++i == limit) <br>
      { <br>
        clearInterval(processor); <br>
 <br>
        result2.value = 'time=' +  <br>
          (new Date().getTime() - start) + ' [done]'; <br>
      } <br>
       <br>
      busy = false; <br>
    } <br>
     <br>
  }, 100); <br>
   <br>
}
登入後複製

優雅?不,但是功能強大嗎?是的。這就是重點。使用此技術,我們可以編寫原本不可能的腳本。

>

android shove silicon綿羊的夢想?

>

>在我們的套件中,我們現在有一種方法來解決以前擺脫可能性領域的JavaScript項目。我開發了這種模式的遊戲具有相當簡單的邏輯,因此一個相當簡單的brain>,但對於常規迭代而言,它仍然太多了。還有很多其他遊戲需要更多的影響力!

>

我的下一個計劃是使用此技術實現JavaScript國際象棋引擎。國際象棋具有各種可能的場景和戰術,導致決策可能需要很長時間才能計算,遠遠超過沒有這種技術的可行性。即使創建最基本的思維機器也需要進行激烈的計算,我承認對可能性感到非常興奮。

>

如果我們能像這樣刪除技巧,誰能說出可能?自然語言處理,啟發式方法……也許我們有在JavaScript中開發人工智能的基礎!

>如果您喜歡閱讀這篇文章,您會喜歡學習的;從大師那裡學習新鮮技能和技術的地方。成員可以立即訪問SitePoint的所有電子書和交互式在線課程,例如Web的JavaScript編程。 >對本文的評論已關閉。有關於JavaScript的疑問嗎?為什麼不在我們的論壇上詢問? 圖片來源:Randen l Peterson > Web工作人員在JavaScript多讀力上的作用是什麼?它們是Web內容在背景線程中運行腳本的簡單手段。工作線程可以執行任務而不會干擾用戶界面。此外,它們可以使用XMLHTTPRequest執行I/O(儘管響應XML和通道屬性始終為null)。創建後,工人可以將消息發送到JavaScript代碼,該消息通過將消息發布給該代碼指定的事件處理程序(反之亦然)。 JavaScript如何處理多線程,儘管是單線讀取? >

> javascript中多線程的限制是什麼? 🎜>雖然可以通過Web Worker來實現JavaScript中的多線程,但重要的是要注意,這些工人無法訪問DOM或其​​他Web API。它們僅限於幾種可以來回發送到主線程的數據類型。另外,每個工人都是一個單獨的實例,因此他們不共享範圍或任何全局變量。

>為什麼javascript支持多本身?

javascript被設計為避免複雜性和潛在的單線閱讀數據操縱問題。多線程可能導致諸如種族條件之類的問題,其中輸出取決於其他不可控制事件的序列或時間。據認為,優化單線讀取環境會更容易,因為無需處理線程之間的依賴項。

>如何在JavaScript中使用Web Worker進行多線程?

>在JavaScript中使用Web Worker進行多線程,您需要創建一個新的Worker對象並指定在工作線程中執行要執行的JavaScript文件。然後,您可以使用tostmessage方法與工作線程進行通信,並使用onMessage事件處理程序從其接收消息。

>多插圖可以使我的JavaScript代碼更快?

多插圖可能會使您的JavaScript代碼可能使您的JavaScript代碼。更快,但這取決於要執行的任務的性質。對於CPU密集型任務,多線程可以通過允許並行執行任務來顯著提高性能。但是,對於I/O結合的任務,多線程的好處不太明顯,因為這些任務通常受到CPU控制以外的因素的限制,例如網絡速度。

>多線程和異步之間有什麼區別在JavaScript?

>多線程和異步編程中的編程是否是同時管理多個任務的技術。但是,他們以不同的方式做到這一點。多線程涉及多個執行線程,每個線程執行不同的任務。另一方面,異步編程涉及單個執行線程,但是可以啟動任務,然後暫停以稍後完成,從而允許在此期間執行其他任務。 JavaScript中的線程之間的數據共享?

> javaScript中線程之間的數據共享可以使用共享arraybuffer和Atomics實現。 sharedArrayBuffer允許在主線程和工作線程之間共享內存,而Atomics則提供了在共享內存上執行安全的原子操作的方法。

我可以在JavaScript中使用多線程進行前端開發嗎? ,您可以在JavaScript中使用多線程進行前端開發。但是,重要的是要注意,啟用多線程的Web工作人員無法訪問DOM或其​​他Web API。因此,它們通常用於不涉及操縱DOM或與網頁進行交互的任務,例如執行計算或處理數據。

以上是JavaScript中的多線程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板