首頁 >web前端 >js教程 >JavaScript 產生器:透過暫停功能增強您的程式碼!

JavaScript 產生器:透過暫停功能增強您的程式碼!

Linda Hamilton
Linda Hamilton原創
2024-12-30 22:29:11995瀏覽

JavaScript Generators: Supercharge Your Code with Pausing Power!

JavaScript 產生器非常酷。它們就像常規函數,但具有超能力。我最近經常使用它們,我不得不說,它們改變了我對程式碼中控制流的思考方式。

讓我們從基礎開始。生成器是一個可以暫停和恢復的函數。它使用 function* 語法和yield 關鍵字。這是一個簡單的例子:

function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
}

const counter = countToThree();
console.log(counter.next().value); // 1
console.log(counter.next().value); // 2
console.log(counter.next().value); // 3

看看我們如何一次單步執行一個yield函數?這就是生成器的魔力。

但是生成器的功能遠不止於計數。它們非常適合建立自訂迭代器。假設您要產生斐波那契數列:

function* fibonacci() {
  let [prev, curr] = [0, 1];
  while (true) {
    yield curr;
    [prev, curr] = [curr, prev + curr];
  }
}

const fib = fibonacci();
for (let i = 0; i < 10; i++) {
  console.log(fib.next().value);
}

這個生成器將永遠持續產生斐波那契數。這是一個無限序列,但我們只計算我們需要的值。

這為我們帶來了生成器最酷的事情之一:惰性求值。他們僅在我們要求時計算值。這對於大型資料集或複雜的計算來說非常有效率。

讓我們來看一個更實際的例子。假設您正在為大型資料集建立分頁系統:

function* paginate(items, pageSize) {
  for (let i = 0; i < items.length; i += pageSize) {
    yield items.slice(i, i + pageSize);
  }
}

const allItems = Array.from({ length: 100 }, (_, i) => i + 1);
const pageSize = 10;
const pages = paginate(allItems, pageSize);

console.log(pages.next().value); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(pages.next().value); // [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

這個生成器讓我們可以根據需要取得資料頁,而無需立即將所有內容載入到記憶體中。

生成器在非同步程式設計方面也很出色。它們可以使非同步程式碼看起來和行為更像同步程式碼。這是使用 co 函式庫的範例:

const co = require('co');

function* fetchUserData() {
  const user = yield fetchUser();
  const posts = yield fetchPosts(user.id);
  const comments = yield fetchComments(posts[0].id);
  return { user, posts, comments };
}

co(fetchUserData).then(result => {
  console.log(result);
}).catch(error => {
  console.error(error);
});

這段程式碼看起來是同步的,但實際上它進行了三個非同步呼叫。生成器在每次收益處暫停,直到承諾解決。

產生器也可以用於協作多工處理。您可以建立多個生成器並在它們之間切換,模擬並發執行:

function* task1() {
  yield 'Start task 1';
  yield 'Middle of task 1';
  yield 'End task 1';
}

function* task2() {
  yield 'Start task 2';
  yield 'Middle of task 2';
  yield 'End task 2';
}

function run(tasks) {
  const iterations = tasks.map(task => task());
  while (iterations.length) {
    const [first, ...rest] = iterations;
    const { value, done } = first.next();
    if (!done) {
      console.log(value);
      iterations.push(first);
    }
    iterations.unshift(...rest);
  }
}

run([task1, task2]);

此程式碼在兩個任務之間交替,一次執行每個步驟。

生成器也非常適合建立狀態機。每個收益可以代表不同的狀態:

function* trafficLight() {
  while (true) {
    yield 'red';
    yield 'green';
    yield 'yellow';
  }
}

const light = trafficLight();
console.log(light.next().value); // red
console.log(light.next().value); // green
console.log(light.next().value); // yellow
console.log(light.next().value); // red

此交通燈將無限期地循環穿過其狀態。

現在,我們來談談一些更高級的技術。生成器委託允許您屈服於另一個生成器:

function* innerGenerator() {
  yield 'inner 1';
  yield 'inner 2';
}

function* outerGenerator() {
  yield 'outer 1';
  yield* innerGenerator();
  yield 'outer 2';
}

const gen = outerGenerator();
console.log(gen.next().value); // outer 1
console.log(gen.next().value); // inner 1
console.log(gen.next().value); // inner 2
console.log(gen.next().value); // outer 2

yield* 語法委託給innerGenerator,在繼續outerGenerator 之前產生其所有值。

生成器中的錯誤處理也值得一提。您可以使用 throw() 方法將錯誤拋出到生成器中:

function* errorGenerator() {
  try {
    yield 'Start';
    yield 'Middle';
    yield 'End';
  } catch (error) {
    console.error('Caught:', error);
    yield 'Error handled';
  }
}

const gen = errorGenerator();
console.log(gen.next().value); // Start
console.log(gen.throw(new Error('Oops!')).value); // Caught: Error: Oops!
                                                  // Error handled

這允許一些非常複雜的錯誤處理策略。

生成器也可以用來實作回溯演算法。這是一個產生所有可能的項目組合的簡單範例:

function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
}

const counter = countToThree();
console.log(counter.next().value); // 1
console.log(counter.next().value); // 2
console.log(counter.next().value); // 3

此產生器將產生給定項目的所有 2 元素組合。

生成器真正發揮作用的一個領域是處理大量資料。您可以建立僅計算所需內容的高效資料處理管道。這是一個逐行處理大檔案的範例:

function* fibonacci() {
  let [prev, curr] = [0, 1];
  while (true) {
    yield curr;
    [prev, curr] = [curr, prev + curr];
  }
}

const fib = fibonacci();
for (let i = 0; i < 10; i++) {
  console.log(fib.next().value);
}

該生成器逐行讀取文件,允許您處理大文件,而無需將它們完全加載到記憶體中。

生成器也可以用來實作 Observable 模式。這是一個簡單的實作:

function* paginate(items, pageSize) {
  for (let i = 0; i < items.length; i += pageSize) {
    yield items.slice(i, i + pageSize);
  }
}

const allItems = Array.from({ length: 100 }, (_, i) => i + 1);
const pageSize = 10;
const pages = paginate(allItems, pageSize);

console.log(pages.next().value); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(pages.next().value); // [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

該生成器充當觀察者,處理它接收到的每個資料。

生成器的另一個很酷的用途是建立自訂控制結構。這是使用生成器的重試函數的範例:

const co = require('co');

function* fetchUserData() {
  const user = yield fetchUser();
  const posts = yield fetchPosts(user.id);
  const comments = yield fetchComments(posts[0].id);
  return { user, posts, comments };
}

co(fetchUserData).then(result => {
  console.log(result);
}).catch(error => {
  console.error(error);
});

此重試函數將在放棄之前嘗試給定的函數最多 maxAttempts 次。

總之,生成器是 JavaScript 的強大功能,可以幫助您編寫更具表現力、更有效率且可維護的程式碼。它們非常適合處理複雜的控制流程、管理非同步操作和處理大型資料集。雖然它們一開始看起來有點奇怪,但一旦您掌握了它們的竅門,您就會發現在專案中使用它們的各種創意方法。因此,繼續吧,在您的下一個 JavaScript 專案中嘗試生成器。您可能會驚訝於他們可以如此簡化您的程式碼!


我們的創作

一定要看看我們的創作:

投資者中心 | 智能生活 | 時代與迴響 | 令人費解的謎團 | 印度教 | 精英開發 | JS學校


我們在媒體上

科技無尾熊洞察 | 時代與迴響世界 | 投資人中央媒體 | 令人費解的謎團 | | 令人費解的謎團 | >科學與時代媒介 |

現代印度教

以上是JavaScript 產生器:透過暫停功能增強您的程式碼!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn