V8引擎詳解(九)——協程&生成器函數

前言

本文是V8引擎詳解系列的第九篇,重點內容是關於生成器函數的運做機制,以及協程的概念。文末會有已經完成的系列文章的連接,本系列文章還在不斷更新歡迎持續關注。javascript

生成器函數Generator

Javascript最初的規則中中,一個函數開始執行後,就會運行到最後或遇到return時結束,運行期間不會有其它代碼可以打斷它。而ES6中引入的Generator(生成器)函數打破了這個規則,Generator函數能夠交出函數的執行權(暫停執行),這也是和普通函數最大的區別。
先說一下Generator的幾個特色:html

  • 調用 Generator 函數,會返回一個內部指針(遍歷器Iterator對象
  • 經過調用 遍歷器Iterator對象 的next方法,遍歷 Generator函數內部的每個狀態
  • 建立時經過 在function關鍵字與函數名添加 "*" 用以和普通函數作區分
  • 函數體內經過多個 yield 表達式,定義不一樣的內部狀態,遍歷器對象 使用next遍歷時即返回當前的 yield 狀態

經過一小段代碼來看一下Generator函數java

function* gen() {
    yield 'first';
    yield 'second';
    yield 1 + 2;
    return 'end';
}

let g = gen();
g.next(); // {value: 'first', done: 'false'};
g.next(); // {value: 'second', done: 'false'};
g.next(); // {value: '3', done: 'false'};
g.next(); // {value: 'end', done: 'true'};
複製代碼

用起來也很簡單,經過構建函數 yiled 構建階段狀態,調用時經過調用next返回當前狀態的信息(value)以及執行狀態(done)。也正是經過Generator函數和Promise的結合完全解決了回調地獄的問題,並於ES7規範推出了官方語法糖async/await
本文主要來聊聊Generator函數究竟是什麼。緩存

進程與線程

想要了解協程就要先了解進程與線程的概念(這幾個概念在計算機中都是屬於比較抽象的概念也歷來沒有統一的標準定義,因此下面只表明我的的觀點與理解)。bash

進程

  • 計算機的核心CPU承擔全部的計算任務(先不說GPU)。
  • 操做系統管理計算機,負責任務的調度,資源的分配和管理。
  • 程序做用於操做系統,用來執行某種功能的集合。
  • 進程是爲了實現程序的某種功能,對於某個數據集合的一次動態執行的過程。
  • 進程是操做系統進行資源分配和調度的一個獨立單位(實體),也是操做系統執行的基本單元,程序是一個沒有生命的實體,只有處理器賦予程序生命時(操做系統執行之),它才能成爲一個活動的實體,咱們稱其爲進程

線程

進程最基本的能力就是 被操做系統調度 以及 進行資源分配和調度,是一個調度資源的基本單位。
做爲一個調度資源的基本單位但願能夠同一時間幹多件事情,因而誕生了 線程 的概念。markdown

線程經過如下特色來幫助進程能夠在同一時間完成多件事情:併發

  • 線程是程序執行的最小單位,而進程是操做系統分配資源的最小單位
  • 一個進程由一個或多個線程組成,線程是一個進程中代碼的不一樣執行路線
  • 進程之間相互獨立,但同一進程下的各個線程之間共享程序的內存空間(包括代碼段、數據集、堆等)及一些進程級的資源(如打開文件和信號),某進程內的線程在其它進程不可見
  • 線程上下文切換比進程上下文切換要快得多

以上即是進程和線程的基本概念,若是以爲我說的仍是比較抽象,能夠參考一下阮大大的進程與線程的一個簡單解釋來幫助理解。async

協程和生成器函數

Generator函數 本質上就是協程的一種實現,若是你能理解協程是什麼那麼你就能輕鬆的理解Generator函數函數

協程究竟是什麼

協程是一種比線程更加輕量級的存在。你能夠把協程當作是跑在線程上的任務,一個線程上能夠存在多個協程,可是在線程上同時只能執行一個協程。高併發

協程概念的提出比較早,單核CPU場景中發展出來的概念,經過提供掛起和恢復接口,實如今單個CPU上交叉處理多個任務的併發功能。
那麼本質上就是在一個線程的基礎上,增長了不一樣任務棧的切換,經過不一樣任務棧的掛起和恢復,線程中進行交替運行的代碼片斷,實現併發的功能。(注意是併發不是並行)

協程的優點

  • 避免鎖競爭

多個線程之間調用資源時會發生競爭關係,會致使鎖的競爭,由於協程自己就是單核cpu上進行操做(在一個線程上同時只能執行一個協程),因此不存在競爭關係。

  • 協程消耗資源遠比線程小

協程的每一個任務棧的佔用的內存空間遠比線程小,在高併發場景,線程太多也會致使OOM

  • 切換成本極低

協程的切換(掛起和恢復)徹底由用戶控制,不須要系統進行切換,成本極低。

javascript中的協程

ES6中引入的生成器函數,就是給用戶提供了協程特性的入口,經過生成器函數讓咱們可使用協程的特性。
這些特性使得程序更適合高併發的I/O操做,更容易的真正解決了回調地獄的問題。

總結

本文主要了解了關於生成器函數的運做機制,以及協程的概念,若是你以前以爲不夠理解生成器函數,讀完本文會發現其實本質上生成器函數不難理解,只要能夠理解協程的概念,也就能明白爲何會出現生成器函數。若是有什麼錯誤,請在評論中和做者一塊兒討論,若是您以爲本文對您有幫助請幫忙點個贊,感激涕零。

系列文章

V8引擎詳解(一)——概述
V8引擎詳解(二)——AST
V8引擎詳解(三)——從字節碼看V8的演變
V8引擎詳解(四)——字節碼是如何執行的
V8引擎詳解(五)——內聯緩存
V8引擎詳解(六)——內存結構
V8引擎詳解(七)——垃圾回收機制
V8引擎詳解(八)——消息隊列
V8引擎詳解(九)——協程&生成器函數

相關文章
相關標籤/搜索