React0.13在Chrome54上抽风问题总结

这几天产品处在发版阶段,工作比较忙,很久没有更新博客了。不过今天在工作中遇到一个最新版Chrome浏览器的坑,分析解决的过程还比较有意思,在这里记录一下。

问题描述

现在在做的项目,项目历时很长,之前选用的ReactJS的0.13.3版本,而现在ReactJS已经升级版本至0.15版本了,但旧版本代码一直运行得好好的,所以一直没有动力进行升级。不过今天Chrome自动升级至54版本后,ReactJS开始报错了。如下:

unhandledRejection.js:23 Potentially unhandled rejection [2] TypeError: Failed to execute 'insertBefore' on 'Node': parameter 1 is not of type 'Node'.
    at insertChildAt (webpack:///./~/react/lib/DOMChildrenOperations.js?:34:14)
    at Object.processUpdates (webpack:///./~/react/lib/DOMChildrenOperations.js?:106:11)
    at Object.dangerouslyProcessChildrenUpdates (webpack:///./~/react/lib/ReactDOMIDOperations.js?:150:27)
    at Object.wrapper [as processChildrenUpdates] (webpack:///./~/react/lib/ReactPerf.js?:70:21)
    at processQueue (webpack:///./~/react/lib/ReactMultiChild.js?:141:31)
    at ReactDOMComponent.updateChildren (webpack:///./~/react/lib/ReactMultiChild.js?:263:13)
    at ReactDOMComponent._updateDOMChildren (webpack:///./~/react/lib/ReactDOMComponent.js?:470:12)
    at ReactDOMComponent.updateComponent (webpack:///./~/react/lib/ReactDOMComponent.js?:319:10)
    at ReactDOMComponent.receiveComponent (webpack:///./~/react/lib/ReactDOMComponent.js?:303:10)
    at Object.receiveComponent (webpack:///./~/react/lib/ReactReconciler.js?:97:22)

跟踪了下调用栈,发现问题出在ReactJS操作DOM的代码处

DOMChildrenOperations.js的105行处

case ReactMultiChildUpdateTypes.INSERT_MARKUP:
        insertChildAt(
          update.parentNode,
          renderedMarkup[update.markupIndex],
          update.toIndex
        );
        break;

这里查看一下update.markupIndex竟然是NaN。继续跟踪ReactMultiChildUpdateTypes.INSERT_MARKUP类型的update是在哪里生成的,于是找到以下代码:

ReactMultiChild.js的40行处

/**
 * Queue of markup to be rendered.
 *
 * @type {array<string>}
 * @private
 */
var markupQueue = [];

/**
 * Enqueues markup to be rendered and inserted at a supplied index.
 *
 * @param {string} parentID ID of the parent component.
 * @param {string} markup Markup that renders into an element.
 * @param {number} toIndex Destination index.
 * @private
 */
function enqueueMarkup(parentID, markup, toIndex) {
  // NOTE: Null values reduce hidden classes.
  updateQueue.push({
    parentID: parentID,
    parentNode: null,
    type: ReactMultiChildUpdateTypes.INSERT_MARKUP,
    markupIndex: markupQueue.push(markup) - 1,
    textContent: null,
    fromIndex: null,
    toIndex: toIndex
  });
}

这里已经标明了生成的update的markupIndex为markupQueue.push(markup) - 1,照理说这肯定不会为NaN的。于是修改代码打印出值看一下。

function enqueueMarkup(parentID, markup, toIndex) {
  var markupIndex = markupQueue.push(markup) - 1;
  console.log(markupIndex);
  // NOTE: Null values reduce hidden classes.
  updateQueue.push({
    parentID: parentID,
    parentNode: null,
    type: ReactMultiChildUpdateTypes.INSERT_MARKUP,
    markupIndex: markupIndex,
    textContent: null,
    fromIndex: null,
    toIndex: toIndex
  });
}

发现竟真的为NaN了,看来应该是Chrome的新版本bug了。为了规避问题,简单修改了下代码后,问题解决:

function enqueueMarkup(parentID, markup, toIndex) {
  var markupIndex = markupQueue.push(markup) - 1;
  if(isNaN(markupIndex)) {
    markupIndex = markupQueue.length - 1;
  }
  // NOTE: Null values reduce hidden classes.
  updateQueue.push({
    parentID: parentID,
    parentNode: null,
    type: ReactMultiChildUpdateTypes.INSERT_MARKUP,
    markupIndex: markupIndex,
    textContent: null,
    fromIndex: null,
    toIndex: toIndex
  });
}

没有改变原来逻辑的本意,仅仅处理了下markupIndex为NaN的情况。

进一步分析

在Chrome的问题列表上搜索了下,果然找到这个问题

总结

ReactJS的源码还挺复杂的,特别是通过虚拟DOM树操作真正DOM那一段。有问题也不要紧,打开Chrome开发者工具,仔细分析还是可以找到问题发生的原因的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java开发者杂谈

扑克牌的问题

问题描述:      假设有A和B来两个人玩牌。游戏的规则是这样的:将一副牌均分成两份,每人拿一份。A先拿出手中的第一张扑克牌,放在桌上,然后B也拿出手中的第一...

426100
来自专栏AhDung

【VBS】vbs指定编码保存文本文件(含xml、ini什么的)

- 让用户填写一些信息,待安装完成后把这些信息写入软件安装目录中的指定ini、xml文件中

12610
来自专栏Java开发者杂谈

分布式改造剧集1

背景介绍 ​ 我所在的项目组,使用的技术一直是接近原始社会的:jdk1.6 + SpringMVC + hessian + Mybatis,当前最火的中间件技术...

30340
来自专栏lonelydawn的前端猿区

javascript对dom节点拖拽的简单实现(drag特性)

直接看代码 ,一切尽在注释中 <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>Dra...

24780
来自专栏草根专栏

使用静态基类方案让 ASP.NET Core 实现遵循 HATEOAS Restful Web API

Hypermedia As The Engine Of Application State (HATEOAS) HATEOAS(Hypermedia as t...

44650
来自专栏工作积累

Android获取QQ和微信的聊天记录,并保存到数据库

(该方法只适用于监控自己拥有的微信或者QQ ,无法监控或者盗取其他人的聊天记录。本文只写了如何获取聊天记录,服务器落地程序并不复杂,不做赘述。写的仓促,有错别字...

5.3K140
来自专栏ytkah

如何用excel urldecode解码把url编码转为汉字?

  统计分析可以反映出网站运营的情况,并根据实际作出相应的调整,是站长必需的基础技能。ytkah感觉最好用的是谷歌统计,里面有个搜索关键词及对应受访页面,这个功...

581100
来自专栏程序员的SOD蜜

如何用ORM支持SQL语句的CASE WHEN?

OQL如何支持CASE WHEN? 今天,一个朋友问我,OQL可否支持CASE WHEN语句?他给的示例SQL如下: select HName,case whe...

26380
来自专栏更流畅、简洁的软件开发方式

【测试】两种数据库,四种分页算法的效率比较

分页算法本身没有什么快慢之分,对反应速度起到决定作用的是——能否有效地利用索引! 算法 评价 缺点 适用的数据库 max 效率最高的 只能有一...

31570
来自专栏歪先生_自留地

Python test2

12030

扫码关注云+社区

领取腾讯云代金券