天天看點

Gulp Stream分析Gulp Stream分析

Gulp Stream分析

标簽(空格分隔): gulp stream

Gulp一個基于流的前端建構工具,可以通過它定制任務。使用的基本格式如下:

var gulp = require("gulp");

// 一個task内部實作
gulp.task("test", function(){
    return gulp.src(String | [])
        .pipe(someHandler)
        .pipe(someOtherHandler)
        .pipe(gulp.dest(String));
});
           

此處我為了簡便起見,列舉了一個task任務,着重強調task内部實作。

由上述代碼,我們看出,gulp通過

gulp.src

,加載一個Stream,然後通過通過

gulp.pipe

方法注入一個類似于管道的處理函數(為什麼是類似于管道?後續讨論),最後将Stream交由

gulp.dest

生成的類似管道處理。

下面我們對gulp的執行流程做一個簡單的介紹。

流程簡介

我們以通過控制台輸入gulp指令為例,輸入gulp taskName,然後按下回車,系統執行流程如下:

  1. 識别指令,分析task清單,解析輸入參數;
  2. 編譯gulpfile,注冊task任務,加載相關子產品;
  3. 根據task清單比對已經注冊的任務,如果存在不比對的情況,則抛出異常;否則執行第4步;
  4. 按照任務清單執行,各任務之間均是異步執行,預設情況下,所指定的任務并不是串行的。
  5. 執行指定的任務,如上文所說的test,調用task對應的函數。
  6. 通過gulp.src生成一個Stream,并且将所比對的檔案以vinyl執行個體的形式加入到流中。
  7. 注冊并pipe,每個pipe中的傳入參數均為一個Transform Stream

分析到這裡,出現了兩個概念,一個是Vinyl File,另外一個是Transform Stream,他們是什麼呢?

Vinyl

” Vinyl is a very simple metadata object that describes a file. When you think of a file, two attributes come to mind: path and contents. These are the main attributes on a Vinyl object. A file does not necessarily represent something on your computer’s file system. You have files on S3, FTP, Dropbox, Box, CloudThingly.io and other services. Vinyl can be used to describe files from all of these sources. ”

大緻意思為:Vinyl是一個檔案的描述對象,包含兩個基本屬性path和contents。它是檔案的抽象表現,可以用之表述為任何形式的檔案對象,如作業系統檔案、網絡檔案等等。

從上可以看出,Vinyl兩個基本屬性:

path

檔案的絕對路徑

contents

檔案的内容,支援Buffer和Stream,也允許為空(null)

除此之外,還提供了一些便利的API,具體請參考Vinyl

Transform Stream

Transform Stream,如字面意思,它是一個轉換流,将輸入chunk進行轉換。

Transform包括兩個核心方法:

transform

function(chunk, encoding, callback),轉換函數,轉換成功後調用callback

function(err, chunk)

,chunk是例如:

var {Transform, Readable} = require("stream");

class MyReader extends Readable {
    constructor(options){
        var op = options || {};
        super(op);
        this._index = typeof op.index === "number" ? op.index : ;
        this._max = typeof op.max === "number" ? op.max : ;
        this._start = this._index;
    }
    _read(){
        if(this._start > this._max){
            this.push(null);
        }
        else{
            this.push(Buffer.from("index" + this._start);
        }
        this._start ++;
    }
}

var transform = new Transform({
    transform: function(chunk, encoding, callback){
        // 執行一些邏輯,執行完之後必須調用callback
        console.info(chunk)
        // callback 參數第一個為err,如果沒有抛出異常,則至null
        callback(null, chunk);
    }, 
    flush: function(callback){
        console.info("end");
        callback(null);
    }
});

var reader = new MyReader({
    index: ,
    max: 
})
reader.pipe(transform)
           

注意事項

  • 在Transform處理函數中運作往Stream新增chunk,通過this.push(chunk, encoding)實作.
  • 通過push的chunk,在本次transform中不會被處理,而是會被接下來的pipe的transform處理。

flush

function(callback),指定flush操作,處理完成之後調用callback。

流的處理流程

介紹了基本概念,再回到gulp的處理流程上來,gulp最主要是流的處理。

Gulp Stream分析Gulp Stream分析

Stream有三個狀态,初始态、暫停态和讀入态。

* 初始态,對應

_readableState.flowing = null

,通過以下方式即可進入讀入态;

1) 注冊data事件

on("data")

2) 調用

read()

方法

3) 調用

pipe()

方法,添加一個管道接收器(pipe destination)。

* 暫停态,對應

_readableState.flowing = false

, 通過以下方式可以進入讀入态;

1) 注冊data事件

on("data")

2) 調用

resume()

方法

3) 調用

pipe()

方法,添加一個管道接收器(pipe destination)。

* 讀入态,對應

_readableState.flowing = true

,一旦從初始态進入讀入态,不可再恢複為初始态,暫停态和讀入态可以互轉。通過以下方式可以進入暫停态;

1) 如果沒有管道接收器(pipe destination),則調用

pause()

方法。

2) 如果添加了管道接收器(pipe destination),則需要移除所有的

data

事件處理函數和所有的管道處理器(pipe destination)。

由此可見,gulp通過

pipe

方法注冊了一系列管道接收器(pipe destination),stream也由初始态進入可讀态。

未完待續。。。