国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

一步一步搭建前端監(jiān)控系統(tǒng):JS錯(cuò)誤監(jiān)控篇

EdwardUp / 1946人閱讀

摘要:摘要徒手寫(xiě)錯(cuò)誤監(jiān)控。為什么用定時(shí)器呢,因?yàn)樵趩雾?yè)應(yīng)用中,路由的切換和地址欄的變化是無(wú)法被監(jiān)控的,我確實(shí)沒(méi)有想到特別好的辦法來(lái)監(jiān)控,所以用了這種方式,如果有人有更好的辦法,請(qǐng)給我留言,謝謝。

摘要: 徒手寫(xiě)JS錯(cuò)誤監(jiān)控。

作者:一步一個(gè)腳印一個(gè)坑

原文:搭建前端監(jiān)控系統(tǒng)(二)JS錯(cuò)誤監(jiān)控篇

Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。

背景:市面上的監(jiān)控系統(tǒng)有很多,大多收費(fèi),對(duì)于小型前端項(xiàng)目來(lái)說(shuō),必然是痛點(diǎn)。另一點(diǎn)主要原因是,功能通用,卻未必能夠滿(mǎn)足我們自己的需求, 所以我們自給自足。

這是搭建前端監(jiān)控系統(tǒng)的第二章,主要是介紹如何統(tǒng)計(jì)js報(bào)錯(cuò),跟著我一步步做,你也能搭建出一個(gè)屬于自己的前端監(jiān)控系統(tǒng)。

請(qǐng)移步線(xiàn)上:前端監(jiān)控系統(tǒng)

對(duì)于前端應(yīng)用來(lái)說(shuō),Js錯(cuò)誤的發(fā)生直接影響前端應(yīng)用的質(zhì)量。對(duì)前端異常的監(jiān)控是整個(gè)前端監(jiān)控系統(tǒng)中的一個(gè)重要環(huán)節(jié)。前端異常包含很多種情況:1. js編譯時(shí)異常(開(kāi)發(fā)階段就能排)2. js運(yùn)行時(shí)異常;3. 加載靜態(tài)資源異常(路徑寫(xiě)錯(cuò)、資源服務(wù)器異常、CDN異常、跨域)4. 接口請(qǐng)求異常等。這一篇我們只介紹Js運(yùn)行時(shí)異常。

監(jiān)控流程:監(jiān)控錯(cuò)誤 -> 搜集錯(cuò)誤 -> 存儲(chǔ)錯(cuò)誤 -> 分析錯(cuò)誤 -> 錯(cuò)誤報(bào)警-> 定位錯(cuò)誤 -> 解決錯(cuò)誤

首先,我們應(yīng)該對(duì)Js報(bào)錯(cuò)情況有個(gè)大致的了解,這樣才能夠及時(shí)的了解前端項(xiàng)目的健康狀況。所以我們需要分析出一些必要的數(shù)據(jù)。

如:一段時(shí)間內(nèi),應(yīng)用JS報(bào)錯(cuò)的走勢(shì)(chart圖表)、JS錯(cuò)誤發(fā)生率、JS錯(cuò)誤在PC端發(fā)生的概率、JS錯(cuò)誤在IOS端發(fā)生的概率、JS錯(cuò)誤在Android端發(fā)生的概率,以及JS錯(cuò)誤的歸類(lèi)。

然后,我們?cè)偃テ渲械腏s錯(cuò)誤進(jìn)行詳細(xì)的分析,輔助我們排查出錯(cuò)的位置和發(fā)生錯(cuò)誤的原因。

如:JS錯(cuò)誤類(lèi)型、 JS錯(cuò)誤信息、JS錯(cuò)誤堆棧、JS錯(cuò)誤發(fā)生的位置以及相關(guān)位置的代碼;JS錯(cuò)誤發(fā)生的幾率、瀏覽器的類(lèi)型,版本號(hào),設(shè)備機(jī)型等等輔助信息

一、JS Error 監(jiān)控功能 (數(shù)據(jù)概覽)

為了得到這些數(shù)據(jù),我們需要在上傳的時(shí)候?qū)⑵浞治龀鰜?lái)。在眾多日志分析中,很多字段及功能是重復(fù)通用的,所以應(yīng)該將其封裝起來(lái)。

// 設(shè)置日志對(duì)象類(lèi)的通用屬性
  function setCommonProperty() {
    this.happenTime = new Date().getTime(); // 日志發(fā)生時(shí)間
    this.webMonitorId = WEB_MONITOR_ID;     // 用于區(qū)分應(yīng)用的唯一標(biāo)識(shí)(一個(gè)項(xiàng)目對(duì)應(yīng)一個(gè))
    this.simpleUrl =  window.location.href.split("?")[0].replace("#", ""); // 頁(yè)面的url
    this.customerKey = utils.getCustomerKey(); // 用于區(qū)分用戶(hù),所對(duì)應(yīng)唯一的標(biāo)識(shí),清理本地?cái)?shù)據(jù)后失效
    this.pageKey = utils.getPageKey();  // 用于區(qū)分頁(yè)面,所對(duì)應(yīng)唯一的標(biāo)識(shí),每個(gè)新頁(yè)面對(duì)應(yīng)一個(gè)值
    this.deviceName = DEVICE_INFO.deviceName;
    this.os = DEVICE_INFO.os + (DEVICE_INFO.osVersion ? " " + DEVICE_INFO.osVersion : "");
    this.browserName = DEVICE_INFO.browserName;
    this.browserVersion = DEVICE_INFO.browserVersion;
    // TODO 位置信息, 待處理
    this.monitorIp = "";  // 用戶(hù)的IP地址
    this.country = "china";  // 用戶(hù)所在國(guó)家
    this.province = "";  // 用戶(hù)所在省份
    this.city = "";  // 用戶(hù)所在城市
    // 用戶(hù)自定義信息, 由開(kāi)發(fā)者主動(dòng)傳入, 便于對(duì)線(xiàn)上進(jìn)行準(zhǔn)確定位
    this.userId = USER_INFO.userId;
    this.firstUserParam = USER_INFO.firstUserParam;
    this.secondUserParam = USER_INFO.secondUserParam;
  }

  // JS錯(cuò)誤日志,繼承于日志基類(lèi)MonitorBaseInfo
  function JavaScriptErrorInfo(uploadType, errorMsg, errorStack) {
    setCommonProperty.apply(this);
    this.uploadType = uploadType;
    this.errorMessage = encodeURIComponent(errorMsg);
    this.errorStack = errorStack;
    this.browserInfo = BROWSER_INFO;
  }
  JavaScriptErrorInfo.prototype = new MonitorBaseInfo();

封裝了一個(gè)Js錯(cuò)誤對(duì)象JavaScriptErrorInfo,用以保存頁(yè)面中產(chǎn)生的Js錯(cuò)誤。其中,setCommonProperty用以設(shè)置所有日志對(duì)象的通用屬性。

1)重寫(xiě)window.onerror 方法, 大家熟知,監(jiān)控JS錯(cuò)誤必然離不開(kāi)它,有人對(duì)他進(jìn)行了測(cè)試測(cè)試介紹感覺(jué)也是比較用心了

2)重寫(xiě)console.error方法,為什么要重寫(xiě)這個(gè)方法,我不能夠給出明確的答案,如果App首次向?yàn)g覽器注入的Js代碼報(bào)錯(cuò)了,window.onerror是無(wú)法監(jiān)控到的,所以只能重寫(xiě)console.error的方式來(lái)進(jìn)行捕獲,也許會(huì)有更好的辦法。待window.onerror成功后,此方法便不再需要用了

3)重寫(xiě)window.onunhandledrejection方法。 當(dāng)你用到Promise的時(shí)候,而你又忘記寫(xiě)reject的捕獲方法的時(shí)候,系統(tǒng)總是會(huì)拋出一個(gè)叫 Unhandled Promise rejection. 沒(méi)有堆棧,沒(méi)有其他信息,特別是在寫(xiě)fetch請(qǐng)求的時(shí)候很容易發(fā)生。 所以我們需要重寫(xiě)這個(gè)方法,以幫助我們監(jiān)控此類(lèi)錯(cuò)誤

下邊是啟動(dòng)JS錯(cuò)誤監(jiān)控代碼

/**
   * 頁(yè)面JS錯(cuò)誤監(jiān)控
   */
  function recordJavaScriptError() {
    // 重寫(xiě)console.error, 可以捕獲更全面的報(bào)錯(cuò)信息
    var oldError = console.error;
    console.error = function () {
      // arguments的長(zhǎng)度為2時(shí),才是error上報(bào)的時(shí)機(jī)
      // if (arguments.length < 2) return;
      var errorMsg = arguments[0] && arguments[0].message;
      var url = WEB_LOCATION;
      var lineNumber = 0;
      var columnNumber = 0;
      var errorObj = arguments[0] && arguments[0].stack;
      if (!errorObj) errorObj = arguments[0];
      // 如果onerror重寫(xiě)成功,就無(wú)需在這里進(jìn)行上報(bào)了
      !jsMonitorStarted && siftAndMakeUpMessage(errorMsg, url, lineNumber, columnNumber, errorObj);
      return oldError.apply(console, arguments);
    };
    // 重寫(xiě) onerror 進(jìn)行jsError的監(jiān)聽(tīng)
    window.onerror = function(errorMsg, url, lineNumber, columnNumber, errorObj)
    {
      jsMonitorStarted = true;
      var errorStack = errorObj ? errorObj.stack : null;
      siftAndMakeUpMessage(errorMsg, url, lineNumber, columnNumber, errorStack);
    };

    function siftAndMakeUpMessage(origin_errorMsg, origin_url, origin_lineNumber, origin_columnNumber, origin_errorObj) {
      var errorMsg = origin_errorMsg ? origin_errorMsg : "";
      var errorObj = origin_errorObj ? origin_errorObj : "";
      var errorType = "";
      if (errorMsg) {
        var errorStackStr = JSON.stringify(errorObj)
        errorType = errorStackStr.split(": ")[0].replace(""", "");
      }
      var javaScriptErrorInfo = new JavaScriptErrorInfo(JS_ERROR, errorType + ": " + errorMsg, errorObj);
      javaScriptErrorInfo.handleLogInfo(JS_ERROR, javaScriptErrorInfo);
    };
  };

OK, 錯(cuò)誤日志有了,該怎么計(jì)算錯(cuò)誤率呢?

JS錯(cuò)誤發(fā)生率 = JS錯(cuò)誤個(gè)數(shù)(一次訪(fǎng)問(wèn)頁(yè)面中,所有的js錯(cuò)誤都算一次)/PV (PC,IOS,Android平臺(tái)同理)

所以我們需要記下頁(yè)面的PV記錄

    /**
       * 添加一個(gè)定時(shí)器,進(jìn)行數(shù)據(jù)的上傳
       * 2秒鐘進(jìn)行一次URL是否變化的檢測(cè)
       * 10秒鐘進(jìn)行一次數(shù)據(jù)的檢查并上傳
       */
      var timeCount = 0;
      setInterval(function () {
        checkUrlChange();
        // 循環(huán)5后次進(jìn)行一次上傳
        if (timeCount >= 25) {
          // 如果是本地的localhost, 就忽略,不進(jìn)行上傳

          var logInfo = (localStorage[ELE_BEHAVIOR] || "") +
            (localStorage[JS_ERROR] || "") +
            (localStorage[HTTP_LOG] || "") +
            (localStorage[SCREEN_SHOT] || "") +
            (localStorage[CUSTOMER_PV] || "") +
            (localStorage[LOAD_PAGE] || "") +
            (localStorage[RESOURCE_LOAD] || "");

          if (logInfo) {
            localStorage[ELE_BEHAVIOR] = "";
            localStorage[JS_ERROR] = "";
            localStorage[HTTP_LOG] = "";
            localStorage[SCREEN_SHOT] = "";
            localStorage[CUSTOMER_PV] = "";
            localStorage[LOAD_PAGE] = "";
            localStorage[RESOURCE_LOAD] = "";
            utils.ajax("POST", HTTP_UPLOAD_LOG_INFO, {logInfo: logInfo}, function (res) {}, function () {})
          }
          timeCount = 0;
        }
        timeCount ++;
      }, 200);

上邊的代碼我用了定時(shí)器,大概的意思是200毫秒進(jìn)行一次URL變化的檢查,5秒進(jìn)行一次數(shù)據(jù)的檢查,如果有數(shù)據(jù)就進(jìn)行上傳,并清空上一次的數(shù)據(jù)。為什么用定時(shí)器呢,因?yàn)樵趩雾?yè)應(yīng)用中,路由的切換和地址欄的變化是無(wú)法被監(jiān)控的,我確實(shí)沒(méi)有想到特別好的辦法來(lái)監(jiān)控,所以用了這種方式,如果有人有更好的辦法,請(qǐng)給我留言,謝謝。

封裝簡(jiǎn)易的Ajax

為了將這些數(shù)據(jù)上傳到我們的服務(wù)器,我們總不能每次都用xmlHttpRequest來(lái)發(fā)送ajax請(qǐng)求吧,所以我們需要自己封裝一個(gè)簡(jiǎn)單的Ajax

/**
     *
     * @param method  請(qǐng)求類(lèi)型(大寫(xiě))  GET/POST
     * @param url     請(qǐng)求URL
     * @param param   請(qǐng)求參數(shù)
     * @param successCallback  成功回調(diào)方法
     * @param failCallback   失敗回調(diào)方法
     */
    this.ajax = function(method, url, param, successCallback, failCallback) {
      var xmlHttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
      xmlHttp.open(method, url, true);
      xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
      xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
          var res = JSON.parse(xmlHttp.responseText);
          typeof successCallback == "function" && successCallback(res);
        } else {
          typeof failCallback == "function" && failCallback();
        }
      };
      xmlHttp.send("data=" + JSON.stringify(param));
    }
二、JS Error 詳細(xì)信息解析

統(tǒng)計(jì)JS Error的目的,一、是為了了解線(xiàn)上項(xiàng)目的健康狀況,二、是為了分析錯(cuò)誤,幫助我們查找問(wèn)題之所在,并且解決它。

所以,如何定位線(xiàn)上的問(wèn)題,并解決問(wèn)題,是我們現(xiàn)在要討論的重點(diǎn)。下面我們需要對(duì)幾個(gè)關(guān)鍵點(diǎn)進(jìn)行分析:

① 某種錯(cuò)誤發(fā)生的次數(shù)——發(fā)生次數(shù)跟影響用戶(hù)是成正比的, 如果發(fā)生次數(shù)跟影響用戶(hù)數(shù)量都很高,那么這是一個(gè)比較嚴(yán)重的bug, 需要立即解決。 反之, 如果次數(shù)很多,影響用戶(hù)數(shù)量很少。說(shuō)明這種錯(cuò)誤只發(fā)生在少量設(shè)備中,優(yōu)先級(jí)相對(duì)較低,可以擇時(shí)對(duì)該類(lèi)機(jī)型設(shè)備進(jìn)行兼容處理。當(dāng)然,ip地址訪(fǎng)問(wèn)次數(shù)也能說(shuō)明這個(gè)問(wèn)題

② 頁(yè)面發(fā)生了哪些錯(cuò)誤——這個(gè)有利于我們縮小問(wèn)題的范圍,方便我們排查,如:

③ 錯(cuò)誤堆?!@點(diǎn)不用說(shuō),是定位錯(cuò)誤最重要的因素。正常情況下,代碼都是被壓縮的,所以我在后臺(tái)解析并截取出錯(cuò)代碼附近的一部分代碼,進(jìn)行展示,排查錯(cuò)誤。PS: 我看到網(wǎng)上有人利用jsMap反向找到代碼的具體位置,想法很不錯(cuò),后期我會(huì)加上。 另外,代碼雖然被壓縮,但是依然很輕松定位到出錯(cuò)的位置,如下圖所示, 所以這個(gè)功能暫時(shí)作為附加題,不用那么著急加上。

④ 設(shè)備信息——當(dāng)錯(cuò)誤發(fā)生是,分析出用戶(hù)當(dāng)時(shí)使用設(shè)備的瀏覽器信息,系統(tǒng)版本,設(shè)備機(jī)型等等,能夠幫我們快速的定位到需要兼容的設(shè)備,進(jìn)而提升解決問(wèn)題的效率。

⑤ 用戶(hù)足跡——我個(gè)人覺(jué)得比較有用,但是代價(jià)太高。 因?yàn)檫@個(gè)需要記錄下用戶(hù)在頁(yè)面上的所有行為,需要上傳非常多的數(shù)據(jù),功能待定。

這個(gè)功能已經(jīng)在后邊進(jìn)行完善了,點(diǎn)擊 查看足跡 按鈕即可查出這個(gè)用的行為足跡,在定位線(xiàn)上問(wèn)題方面,有很大的作用 , 我在后邊的篇幅中有介紹 搭建前端監(jiān)控系統(tǒng)(五)怎樣定位線(xiàn)上問(wèn)題

到此,已經(jīng)收集到了JS錯(cuò)誤日志的大部分信息了,并且已經(jīng)分析出JS錯(cuò)誤的詳細(xì)信息了。

三、JS報(bào)錯(cuò)的實(shí)時(shí)監(jiān)控與報(bào)警

既然我們已經(jīng)具有了搜集js報(bào)錯(cuò)和分析報(bào)錯(cuò)的能力了,那么我們也可以做到Js報(bào)錯(cuò)實(shí)時(shí)監(jiān)控,以及實(shí)時(shí)預(yù)警了,這樣可以防范線(xiàn)上事故于未然,及時(shí)的制止線(xiàn)上事故的持續(xù)發(fā)生, 減少損失。

如上圖所示,我展示了從當(dāng)前時(shí)間向前推算24小時(shí),每小時(shí)報(bào)錯(cuò)數(shù)量。另外展示了7天前同一時(shí)間段的報(bào)錯(cuò)數(shù)量,如果你的項(xiàng)目健康穩(wěn)定,那么在相同時(shí)間段的報(bào)錯(cuò)數(shù)量應(yīng)該不會(huì)相差太大。如果出現(xiàn)相差太大的情況發(fā)生,說(shuō)明線(xiàn)上出現(xiàn)了問(wèn)題,此刻應(yīng)該發(fā)出警告,避免線(xiàn)上事故的發(fā)生。demo上暫未加上警告功能,但是原理清楚了,后邊自然水到渠成。

關(guān)于Fundebug

Fundebug專(zhuān)注于JavaScript、微信小程序、微信小游戲、支付寶小程序、React Native、Node.js和Java線(xiàn)上應(yīng)用實(shí)時(shí)BUG監(jiān)控。 自從2016年雙十一正式上線(xiàn),F(xiàn)undebug累計(jì)處理了10億+錯(cuò)誤事件,付費(fèi)客戶(hù)有陽(yáng)光保險(xiǎn)、核桃編程、荔枝FM、掌門(mén)1對(duì)1、微脈、青團(tuán)社等眾多品牌企業(yè)。歡迎大家免費(fèi)試用!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/105340.html

相關(guān)文章

  • 步一搭建前端監(jiān)控系統(tǒng):如何記錄用戶(hù)行為?

    摘要:摘要通過(guò)記錄用戶(hù)行為,快速?gòu)?fù)現(xiàn)場(chǎng)景。這是搭建前端監(jiān)控系統(tǒng)的第二章,主要是介紹如何統(tǒng)計(jì)報(bào)錯(cuò),跟著我一步步做,你也能搭建出一個(gè)屬于自己的前端監(jiān)控系統(tǒng)。 摘要: 通過(guò)記錄用戶(hù)行為,快速?gòu)?fù)現(xiàn)BUG場(chǎng)景。 作者:一步一個(gè)腳印一個(gè)坑 原文:搭建前端監(jiān)控系統(tǒng)(備選)用戶(hù)行為統(tǒng)計(jì)和監(jiān)控篇(如何快速定位線(xiàn)上問(wèn)題) Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。 一步一步搭建前端監(jiān)控系統(tǒng)系列博客: ...

    tolerious 評(píng)論0 收藏0
  • 步一搭建前端監(jiān)控系統(tǒng):如何定位前端線(xiàn)上問(wèn)題?

    摘要:一直以來(lái),前端的線(xiàn)上問(wèn)題很難定位,因?yàn)樗l(fā)生于用戶(hù)的一系列操作之后。當(dāng)然,這些問(wèn)題并非不能克服,讓我們來(lái)一起看看如何去定位線(xiàn)上的問(wèn)題吧。地址參考一步一步搭建前端監(jiān)控系統(tǒng)錯(cuò)誤監(jiān)控篇一步一步搭建前端監(jiān)控系統(tǒng)接口請(qǐng)求異常監(jiān)控篇 摘要: 記錄用戶(hù)行為,排查線(xiàn)上BUG。 作者:一步一個(gè)腳印一個(gè)坑 原文:如何定位前端線(xiàn)上問(wèn)題(如何排查前端生產(chǎn)問(wèn)題) Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所...

    aaron 評(píng)論0 收藏0
  • 步一搭建前端監(jiān)控系統(tǒng):接口請(qǐng)求異常監(jiān)控

    摘要:參考一步一步搭建前端監(jiān)控系統(tǒng)錯(cuò)誤監(jiān)控篇用插件記錄網(wǎng)絡(luò)請(qǐng)求異常關(guān)于專(zhuān)注于微信小程序微信小游戲支付寶小程序和線(xiàn)上應(yīng)用實(shí)時(shí)監(jiān)控。 摘要: 如何監(jiān)控HTTP請(qǐng)求錯(cuò)誤? 作者:一步一個(gè)腳印一個(gè)坑 原文:搭建前端監(jiān)控系統(tǒng)(四)接口請(qǐng)求異常監(jiān)控篇 Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。 背景:市面上的監(jiān)控系統(tǒng)有很多,大多收費(fèi),對(duì)于小型前端項(xiàng)目來(lái)說(shuō),必然是痛點(diǎn)。另一點(diǎn)主要原因是,功能雖然...

    dreamtecher 評(píng)論0 收藏0
  • 步一搭建前端監(jiān)控系統(tǒng):如何將網(wǎng)頁(yè)截圖上報(bào)?

    摘要:目前已經(jīng)在運(yùn)行的線(xiàn)上前端監(jiān)控系統(tǒng)代碼和講解都放在這篇文章里監(jiān)控系統(tǒng)介紹及代碼用戶(hù)對(duì)前端程序員來(lái)說(shuō),就是一個(gè)黑匣子。 摘要: 通過(guò)錄屏或者截圖,快速?gòu)?fù)現(xiàn)BUG場(chǎng)景。 作者:一步一個(gè)腳印一個(gè)坑 原文:搭建前端監(jiān)控系統(tǒng)(備選)Js截圖上報(bào)篇 Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。 PS:本文關(guān)于Fundebug錄屏功能的內(nèi)容有些不準(zhǔn)確的地方,比如錄屏并非通過(guò)截圖實(shí)現(xiàn)的,錄屏插件...

    Martin91 評(píng)論0 收藏0
  • 前端每周清單半年盤(pán)點(diǎn)之 Node.js

    摘要:前端每周清單專(zhuān)注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開(kāi)發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開(kāi)發(fā)教程工程實(shí)踐深度閱讀開(kāi)源項(xiàng)目巔峰人生等欄目。對(duì)該漏洞的綜合評(píng)級(jí)為高危。目前,相關(guān)利用方式已經(jīng)在互聯(lián)網(wǎng)上公開(kāi),近期出現(xiàn)攻擊嘗試爆發(fā)的可能。 前端每周清單專(zhuān)注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開(kāi)發(fā)者了解一周前端熱點(diǎn);分為新聞熱點(diǎn)、開(kāi)發(fā)教程、工程實(shí)踐、深度閱讀、開(kāi)源項(xiàng)目、巔峰人生等欄目。歡...

    kid143 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<