成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

從一次重寫(xiě)原生方法遇到的坑,總結(jié)一下Web中的事件系統(tǒng)

oysun / 625人閱讀

摘要:?jiǎn)栴}初探索刪掉那一點(diǎn)重寫(xiě)的代碼后,表現(xiàn)符合預(yù)期了。每一次都重新造一個(gè)虛擬的,然后監(jiān)聽(tīng)其自定義事件,并且立即觸發(fā)這個(gè)自定義事件。真的不要隨便重寫(xiě)原生方法。。。于是,我全面總結(jié)一下了中的事件系統(tǒng),也算是對(duì)基礎(chǔ)的鞏固。

寫(xiě)在前面

前段時(shí)間,我寫(xiě)過(guò)一篇文章前端開(kāi)發(fā)中的Error以及異常捕獲。 在文章中,我提到了這個(gè)問(wèn)題:

經(jīng)過(guò)不斷探索(不想再噴自己了),我找到了原因。下面一一道來(lái)。本文主要講解自己找問(wèn)題原因的思路,如果想看結(jié)論和總結(jié),請(qǐng)直接跳到文末。

問(wèn)題復(fù)現(xiàn)

我是在自己以前的項(xiàng)目中測(cè)試addEventListener的重寫(xiě)的。這里直接上精簡(jiǎn)后的問(wèn)題代碼:

import React from "react";
import ReactDOM from "react-dom";

const nativeAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function (type, func, options) {
    const wrappedFunc = function (...args) {
        try {
             return func.apply(this, args);
        } catch (e) {
             const errorObj = {
                 error_msg: e.message || "",
                 error_stack: e.stack || (e.error && e.error.
                 error_native: e
             };
        }
    }
    return self.nativeAddEventListener.call(this, type, wrappedFunc, options);
};

const App = function() {
    return 
11111
}; ReactDOM.render(, document.body);

運(yùn)行這段代碼,瀏覽器上一片空白,但是卻沒(méi)有任何報(bào)錯(cuò)。我一臉懵逼。

問(wèn)題初探索

刪掉那一點(diǎn)重寫(xiě)addEventListener的代碼后,表現(xiàn)符合預(yù)期了。應(yīng)該是重寫(xiě)那兒的問(wèn)題。但是仔細(xì)看了過(guò)后,那段代碼并沒(méi)有什么問(wèn)題。并且這段代碼我在其他地方也試過(guò),表現(xiàn)一直是正常的。是不是和React哪里沖突了?我使用的React版本是

我搜索了react-dom源碼中的addEventListener關(guān)鍵字,總共出現(xiàn)了四次。初步看了一下,并沒(méi)有什么問(wèn)題,只是注冊(cè)了一些事件而已。沒(méi)有具體分析這些代碼的含義,我選擇了先更換React的版本試一試,于是,我換成了15.6.2的版本。令人吃驚的是,表現(xiàn)符合預(yù)期了。難道真的和React的版本有關(guān)系? 在我的認(rèn)知中,兩個(gè)版本中最大的不同就是:React v16采用了全新的Fiber架構(gòu),而我對(duì)Fiber的理解大概就是:重新設(shè)計(jì)了react node的數(shù)據(jù)結(jié)構(gòu),模擬實(shí)現(xiàn)了自己的任務(wù)堆棧,結(jié)合時(shí)間分片來(lái)進(jìn)行任務(wù)的調(diào)度,從而更新整個(gè)系統(tǒng)。另外,React有自己的一套事件系統(tǒng),addEventListener和事件也是緊密相關(guān)的,難道影響到了這個(gè)?

繼續(xù)探索

我決定從ReactDOM.render()這個(gè)方法入手,調(diào)試一下ReactDOM的源代碼。之前并沒(méi)有研究過(guò)React的源碼,壓力有點(diǎn)大。調(diào)試了一翻之后,我并沒(méi)有發(fā)現(xiàn)什么問(wèn)題,并且已經(jīng)有點(diǎn)懵逼了。我準(zhǔn)備同時(shí)調(diào)試react v15react v16的代碼,看看有什么不同。為了方便,我將問(wèn)題代碼全部抽了出來(lái),全部寫(xiě)到了一個(gè)html文件中,并且直接引用React的cdn地址。這個(gè)時(shí)候,我發(fā)現(xiàn)了一個(gè)神奇的問(wèn)題:直接引用cdn地址后,不管React是什么版本,就算是v16版本,也不會(huì)出現(xiàn)之前問(wèn)題,表現(xiàn)都是符合預(yù)期的。我更加懵逼了。

發(fā)現(xiàn)問(wèn)題

靜下心來(lái)仔細(xì)觀察后,我發(fā)現(xiàn)了,我cdn引用的都是reactproduction版本,而我在項(xiàng)目中使用的react代碼,卻是development版本的,難道是developmentproduction的diff代碼,導(dǎo)致了上面的問(wèn)題。于是我重新仔細(xì)看了一下v16development的代碼,找到了代碼中一段長(zhǎng)長(zhǎng)的注釋:

大意就是:在開(kāi)發(fā)版本中,react不會(huì)采用try{}catch(){}的方式來(lái)捕獲錯(cuò)誤,而是會(huì)把所有開(kāi)發(fā)者定義的callback用一個(gè)叫做invokeGuardedCallback的函數(shù)包裹起來(lái),然后使用一個(gè)假的dom,監(jiān)聽(tīng)、觸發(fā)自定義事件來(lái)執(zhí)行invokeGuardedCallback,并且通過(guò)一個(gè)全局的錯(cuò)誤捕捉函數(shù)來(lái)捕獲錯(cuò)誤。

在這段注釋的下面,就是注釋中提到的invokeGuardedCallback的代碼。

我仔細(xì)研究了這個(gè)invokeGuardedCallback的代碼,其核心就是:

function invokeGuardedCallback(name, func, context, a, b, c, d, e, f){
     ...
     var fakeNode = document.createElement("react");
     var evt = document.createEvent("Event");
     var evtType = "react-" + (name ? name : "invokeguardedcallback");
     var callCallback = function(){
        ...
        fakeNode.removeEventListener(evtType, callCallback, false); // 這里很重要?。?!
        ...
        func.apply(context, funcArgs); // 這里是真正執(zhí)行react中的邏輯代碼
     } 
     fakeNode.addEventListener(evtType, callCallback, false);
     evt.initEvent(evtType, false, false);
     fakeNode.dispatchEvent(evt);
     ...
}
 

react將所有容易出錯(cuò)的函數(shù),都用這個(gè)invokeGuardedCallback包了起來(lái)。每一次都重新造一個(gè)虛擬的element,然后監(jiān)聽(tīng)其自定義事件,并且立即觸發(fā)這個(gè)自定義事件。調(diào)試了這個(gè)invokeGuardedCallback后,我發(fā)現(xiàn)在react v16中,發(fā)現(xiàn)很多函數(shù)被多次執(zhí)行。
為什么會(huì)多次執(zhí)行呢? 終于,我找到了問(wèn)題的原因:

我重寫(xiě)了addEventListener, 在函數(shù)外包了一層try{}catch(){},返回的是一個(gè)新的函數(shù),所以,最終注冊(cè)在事件監(jiān)聽(tīng)器上的,并不是我傳入的那個(gè)函數(shù)。這個(gè)時(shí)候,調(diào)用removeEventListener時(shí),無(wú)法移除我傳入addEventListener的函數(shù)。

invokeGuardedCallback中,removeEventListener的邏輯相當(dāng)于并沒(méi)有生效。于是,在Fiber的調(diào)度中,某個(gè)函數(shù)被多次重復(fù)執(zhí)行了,而被重復(fù)執(zhí)行的函數(shù)并不是冪等的,問(wèn)題便產(chǎn)生了。

問(wèn)題的總結(jié)與思考

問(wèn)題終于定位了,一句總結(jié),就是:

重寫(xiě)了addEventListener,卻并沒(méi)有考慮到與之對(duì)應(yīng)的removeEventListener,導(dǎo)致removeEventListener無(wú)法正常工作。

下面是一些思考:

一開(kāi)始,如果我仔細(xì)看一下react源碼中addEventListener周圍的代碼,或許能更早發(fā)現(xiàn)這個(gè)問(wèn)題,就不用繞這么大一個(gè)圈了。

自己對(duì)于第三方庫(kù)的development版本和production版本,并沒(méi)有一個(gè)很強(qiáng)烈的認(rèn)知、意識(shí),以前上線的不少項(xiàng)目,線上竟然還是用的第三方庫(kù)的development版本,這個(gè)毛病,一定得改掉。

分析問(wèn)題的能力還很欠缺,不夠敏感??紤]問(wèn)題的全面性需要提高。

真的不要隨便重寫(xiě)原生方法。。。

寫(xiě)在后面

在探索這個(gè)問(wèn)題的過(guò)程中,我看到了react巧妙應(yīng)用自定義事件來(lái)捕獲錯(cuò)誤。于是,我全面總結(jié)一下了Web中的事件系統(tǒng),也算是對(duì)基礎(chǔ)的鞏固。由于篇幅已經(jīng)不夠了,這里就直接放文章鏈接吧:

談一談web中的事件
談一談web中的事件

歡迎關(guān)注我的公眾號(hào): 符合預(yù)期的CoyPan
這里只有干貨,符合你的預(yù)期。

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

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

相關(guān)文章

  • JavasScript重難點(diǎn)知識(shí)

    摘要:忍者級(jí)別的函數(shù)操作對(duì)于什么是匿名函數(shù),這里就不做過(guò)多介紹了。我們需要知道的是,對(duì)于而言,匿名函數(shù)是一個(gè)很重要且具有邏輯性的特性。通常,匿名函數(shù)的使用情況是創(chuàng)建一個(gè)供以后使用的函數(shù)。 JS 中的遞歸 遞歸, 遞歸基礎(chǔ), 斐波那契數(shù)列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果...

    forsigner 評(píng)論0 收藏0
  • 總結(jié)移動(dòng)開(kāi)發(fā)實(shí)踐中遇到的坑

    摘要:博主之前已經(jīng)推薦了一款神器下面,就總結(jié)一下移動(dòng)端遇見(jiàn)的坑。解決原理虛擬鍵盤(pán)彈出時(shí)將元素設(shè)置為,虛擬鍵盤(pán)消失時(shí)候設(shè)置回來(lái)。解決方案由于虛擬鍵盤(pán)出現(xiàn)并未拋出事件,而檢測(cè)或者事件,皆會(huì)有一定延遲,會(huì)出現(xiàn)閃爍現(xiàn)象。 做過(guò)很多移動(dòng)端的項(xiàng)目,在開(kāi)發(fā)調(diào)試過(guò)程中,一款好的調(diào)試工具會(huì)讓效率大大提高。博主之前已經(jīng)推薦了一款神器:http://web.jobbole.com/87587/ 下面,就總結(jié)一下移...

    rockswang 評(píng)論0 收藏0
  • 2016年終工作總結(jié)

    摘要:由于初版需求及開(kāi)發(fā)工作都沒(méi)有參與,在接手項(xiàng)目后過(guò)了遍前端結(jié)構(gòu)發(fā)現(xiàn)所有交互及組件都是現(xiàn)擼,并未使用市面上已有的優(yōu)秀前端框架從我個(gè)人角度理解上出發(fā),后續(xù)需求變更中當(dāng)需要實(shí)現(xiàn)某些常用組件樣式或交互時(shí),基本上都需要現(xiàn)擼或者尋找合適的組件。 2016悄無(wú)聲息的過(guò)去了,再過(guò)不久便是農(nóng)歷新年 這幾天相對(duì)清閑梳理了一下去年所做的工作,希望在新的一年能發(fā)展的更好 今年一共研發(fā)或升級(jí)了五款產(chǎn)品:合伙人、奪...

    hoohack 評(píng)論0 收藏0
  • FEDAY2016之旅

    摘要:前戲補(bǔ)上參會(huì)的完整記錄,這個(gè)問(wèn)題從一開(kāi)始我就是準(zhǔn)備自問(wèn)自答的,希望可以通過(guò)這種形式把大會(huì)的干貨分享給更多人。 showImg(http://7xqy7v.com1.z0.glb.clouddn.com/colorful/blog/feday2.png); 前戲 2016/3/21 補(bǔ)上參會(huì)的完整記錄,這個(gè)問(wèn)題從一開(kāi)始我就是準(zhǔn)備自問(wèn)自答的,希望可以通過(guò)這種形式把大會(huì)的干貨分享給更多人。 ...

    red_bricks 評(píng)論0 收藏0
  • 移動(dòng)端開(kāi)發(fā)(使用webuploader上傳圖片,客戶端交互,修改alert彈窗等)

    摘要:之前實(shí)習(xí)做的一個(gè)移動(dòng)端的頁(yè)面需要的功能有圖片上傳點(diǎn)擊客戶端的返回按鈕有提示即與客戶端有交互遇到不少的坑總結(jié)一下問(wèn)題圖片上傳功能使用工具百度的暫時(shí)遇到的坑刪除圖片實(shí)際上并沒(méi)有完全刪除需要自己在源碼上添加詳情看的提問(wèn)上傳的圖片旋轉(zhuǎn)角度有問(wèn)題比 之前實(shí)習(xí)做的一個(gè)移動(dòng)端的頁(yè)面 需要的功能有圖片上傳 點(diǎn)擊客戶端的返回按鈕 有提示(即與客戶端有交互) 遇到不少的坑 總結(jié)一下問(wèn)題 1.圖片上傳功能 ...

    李昌杰 評(píng)論0 收藏0

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

0條評(píng)論

oysun

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<