記一次 JSON.stringify 引起的問題

前言

目前在開發一個生成骨架屏的 webpack 插件,使用 Puppeteer 來將處理腳本經過 addScriptTag 方法來插入到頁面中。webpack

想法是想模仿 webpack 能夠經過配置 plugins 來添加自定義的處理規則,問題就出在這裏,經過 page.evaluate 來執行頁面腳本的時候獲取不到我傳入的 pluginsgit

問題

webpack plugin configgithub

class TestPlugin {
    apply(api, ele, options) {
        console.log(api, ele, options);
    }
}
{
    ...
    port: 8899,
    plugins: [
        function test(api, ele, options) {
            console.log(api, ele, options);
        },
        new TestPlugin()
    ],
    ...
}
複製代碼

使用 puppeteer 的代碼:web

await page.evaluate(options => {
  Skeleton.genSkeleton(options);
}, this.options);
複製代碼

在調用 Skeleton.genSkeleton 方法的時候, options.plugins 變成了 [null, {}]。致使獲取不到傳遞的自定義處理函數。api

排查問題

首先確認 webpack 是否接受到參數

由此能夠發現 wepack 已經接受到了配置的參數

那就只能是 Puppeteer 的問題了

查看了 puppetter 的官方文檔。數組

明確說明了 evaluate 方法接受的參數必須是能夠被序列化的。

而後去 github 上查看它的源碼發現它使用 JSON.stringify 來進行序列化。bash

那麼確認是 JSON.stringify 的問題了。

進一步分析問題

既然肯定是 JSON.stringify 的問題了, 趕忙去看一波 JSON.stringify 的文檔。 送上 JSON.stringify() 的MDN地址app

由此能夠發現當函數出如今非數組對象時,在序列化的過程當中會被忽略,因此 plugins 第二個元素返回 {}, 當函數出如今數組對象中時,在序列化過程當中會被轉換成 null,因此 plugins 的第一個元素返回 null

總結

思考一下,爲何有些屬性不能被 stringify 序列化。函數

由於 JSON 是一個通用的文本格式,和語言無關。設想若是將函數定義也 stringify 的話,如何判斷是哪一種語言,而且經過合適的方式將其呈現出來將會變得特別複雜。特別是和語言相關的一些特性,好比 JavaScript 中的 Symbolui

ECMASCript官方也特地強調了這一點:

It does not attempt to impose ECMAScript's internal data representations on other programming languages. Instead, it shares a small subset of ECMAScript's textual representations with all other programming languages.

有興趣的小夥伴能夠了解一下如何使用 toJSON 來自定義序列化行爲。

相關文章
相關標籤/搜索