首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

JavaScript 執行速度過快導致 jQuery 賦值失效?解決競態條件的實戰技巧

     編輯:程式設計綜合問答

現象:jQuery 批量賦值時第 22 個 input 卻讀不到值

開發者在使用 jQuery 連續給一組 input 元素賦值時,發現陣列的第 22 項(array[22])明明有資料,賦值語句卻一直寫入空值。更詭異的是,若在該行前插入一個 alert() 做「延遲」,賦值反而成功了。這真的是「JS 執行太快」導致的嗎?

核心原因:非同步渲染與事件迴圈的競態條件

JavaScript 是單執行緒、非阻塞的語言。當你用迴圈批量操作 DOM 時,瀏覽器不會在每次賦值後立即重繪,而是將所有同步代碼推入呼叫堆疊一次性執行完畢,才會在下一個微任務/宏任務階段進行佈局與繪製。若後續邏輯(如讀取 array[22])依賴 DOM 已經真正更新完畢,卻在同一個同步區塊裡直接執行,就會拿到舊狀態——這就是典型的「競態條件」。

alert() 之所以能「緩解」,是因為它會阻塞主執行緒並強制瀏覽器進入一個新的事件迴圈迭代,給渲染引擎留出了繪製時間,讓 DOM 狀態趕上來。

正規解法:不要依賴阻塞式 Hack

1. 使用 requestAnimationFrame 或 setTimeout(fn, 0) 推延到下一幀

// 錯誤示範
for (let i = 0; i < inputs.length; i++) {
  $(inputs[i]).val(data[i]); // 同步批量寫入
}
console.log($(inputs[22]).val()); // 可能仍為空

// 正確寫法:分批或推延讀取
function batchAssign(inputs, data, idx = 0) {
  const chunk = 50; // 每幀處理 50 個
  for (let i = 0; i < chunk && idx < inputs.length; i++, idx++) {
    $(inputs[idx]).val(data[idx]);
  }
  if (idx < inputs.length) {
    requestAnimationFrame(() => batchAssign(inputs, data, idx));
  } else {
    // 全部寫入完成,安全讀取
    console.log($(inputs[22]).val());
  }
}
batchAssign(inputs, data);

2. 若資料來源本身是非同步(AJAX/Promise),務必 await 後再操作 DOM

async function loadAndFill() {
  const res = await fetch('/api/data');
  const arr = await res.json();
  // 這時 arr 已就緒,同步寫入即可
  inputs.forEach((el, i) => $(el).val(arr[i]));
}

3. 使用 MutationObserver 監聽特定元素屬性變化

若必須在「第 22 個 input 真正顯示新值」的瞬間觸發後續邏輯,可掛載觀察器:

const target = inputs[22];
const observer = new MutationObserver(() => {
  if (target.value) {
    console.log('第 22 項已更新:', target.value);
    observer.disconnect();
  }
});
observer.observe(target, { attributes: true, attributeFilter: ['value'] });

最佳實踐總結

  • 不要用 alert()、debugger 當生產環境延遲手段,會嚴重阻塞主執行緒並破壞使用者體驗。
  • 大量 DOM 操作請分批、分幀,配合 requestAnimationFrame 或 requestIdleCallback。
  • 資料與視圖分離:先備妥資料陣列,再一次性 innerHTML 或 DocumentFragment 寫入,減少重排重繪。
  • 若框架支援(Vue/React/Angular),交給響應式系統處理,避免手動操作 DOM。

掌握事件迴圈機制,才能從根源上避免「速度太快賦不上值」這類看似玄學、實則邏輯時序錯誤的坑。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved