从ES规范和引擎细谈 js 中 parseInt 和 parseFloat 的执行机制

article/2025/8/25 19:52:10

从ES规范和引擎细谈 js 中 parseInt 和 parseFloat 的执行机制

parseInt()parseFloat()这两个常用 API 其实还是有很多“坑”的,以此文统一梳理一下。(本文比较适合常与数字打交道的 jser 或对这两 API 运作感兴趣的同学)

(github:https://github.com/MichealWayne,个人博客地址:https://blog.michealwayne.cn/),转载可联系michealwayne@163.com

执行检验

在以前描述 js 数值时(Q3.说出以下转换数字数值转换的结果),有提到 parseIntparseFloat的运行机制,其实这两 API 还是有蛮多坑的,虽然平时不太会踩到。

首先猜测以下的执行,自我检验一番:

/* parseInt */
parseInt('123.456.789');
parseInt('+123.456.789');
parseInt('123abc');
parseInt('abc123');
parseInt('1e6');
parseInt('    1    ');
parseInt('');
parseInt('0');
parseInt('0x');
parseInt('0x11');
parseInt(new String('123'));parseInt('a', 16);
parseInt(123.456, -1);
parseInt(123.456, 0);
parseInt(123.456, 1);
parseInt(123.456, 2);
parseInt(123.456, 40);
parseInt(123.456, 36);
parseInt(1e6);
parseInt(1n);
parseInt();
parseInt(null);
parseInt(false);// 有几个“超纲”题
parseInt(0.00000001);
parseInt(123.456, -99999999999999999999999999);
parseInt(123.456, 99999999999999999999999999);
parseInt(123.456, 9999999999999999999999999);
parseInt(9999999999999999);
parseInt('11111111111111111');
parseInt('11111111111111111111');
parseInt(1e21);
parseInt('123aef', 12);
parseInt('123', NaN);
parseInt('0xf', NaN);
parseInt('123', Infinity);
parseInt('111', 2 ** 32 + 2.1);
parseInt(Symbol());
parseInt(parseInt);
const objTest1 = {};
parseInt(objTest1);
objTest1.toString = () => 123;
parseInt(objTest1);/* parseFloat */
parseFloat('123.456.789');
parseFloat('123abc.456.789');
parseFloat('    123abc    ');
parseFloat('1e6');
parseFloat('+Infinity');
parseFloat(Infinity);
parseFloat(123.456);
parseFloat(1e6);
parseFloat(0.00000001);
parseFloat(0.1 + 0.2);
parseFloat('0x1a');
parseFloat(1n);
parseFloat();
parseFloat(null);
parseFloat(false);// 有几个“超纲”题
parseFloat(9999999999999999);
parseFloat('11111111111111111');
parseFloat('11111111111111111111');
parseFloat(Symbol());
parseFloat(parseFloat);
const objTest2 = {};
parseFloat(objTest2);
objTest2.toString = () => 123;
parseFloat(objTest2);

ECMAScript 规范

无论啥内核、浏览器或是 NodeJs,都会遵循 ECMA 的主要规范,因此要思考上列的执行结果,可以重点了解 ECMA 规范的执行描述。

parseInt()

语法:

parseInt(string, radix)

其中参数:

  • string:要被解析的值。如果参数不是一个字符串,则将其转换为字符串。标准输入:
    p-parseInt-input-string

  • radix可选,介于2~36之间的整数。告知parseInt()函数string(比如 11)是radix(比如 2)进制的表示,如果radix不存在,parseInt将固定返回string以十进制显示的数。

另外:

parseInt === Number.parseInt; // => true

ECMAScript(6.0) 规范说明

parseInt1

简单翻译一下执行步骤:

  • 1.定义变量inputString,它是入参string执行 ToString(string) 的字符串结果。(ToString是一个内部 abstract operations、不对外,具体执行见文档或文末附录);
  • 2.执行出现异常则返回(ReturnIfAbrupt,关于ReturnIfAbrupt的执行其实还蛮复杂的,涉及 ECMA 规范的规格术语,本文不做描述);
  • 3.定义变量S,它是inputString创建的一个子字符串,它由第一个不是空白字符的代码单元和该代码单元之后的所有代码单元组成,即去除前置空格,也就是说parseInt('123')parseInt(' 123')效果相同。如果找不到这样的单元,则S为空字符串("");
  • 4.定义变量sign1
  • 5.如果变量S不为空并且S的第一个单元是0x002DHYPHEN-MINUS,即减号),变量sign改为-1
  • 6.如果变量S不为空并且S的第一个单元是0x002BPLUS SIGN,即加号) 或0x002D (HYPHEN-MINUS,即减号),去除S的第一个单元,即去除'+'/-符号;
  • 7.定义变量RToInt32(radix),即对进制声明进行ToInt32数字转换,也就是说parseInt('123', 8)parseInt('123', '8')效果相同;
  • 8.执行出现异常则返回(ReturnIfAbrupt);
  • 9.定义变量stripPrefixtrue
  • 10.如果变量R不等于0,则:
    • 如果变量R小于 2 或大于 36,直接返回NaN
    • 如果变量R不等于 16,变量stripPrefix 改为 false
  • 11.如果变量R等于0,则变量R改为10
  • 12.如果变量stripPrefix值为true,则:
    • 如果变量S字符串长度不小于 2 并且前两个字符单元是0x0X,则删除这两字符,且设置变量R16
  • 13.设置变量Z,如果变量S包含一个不是变量R数字的字符单元,则ZS的子字符串,且由第一个这样的字符单元之前的所有代码单元组成,即parseInt('789', 8)parseInt('7', 8)效果相同;否则,ZS
  • 14.如果变量Z为空,直接返回NaN
  • 15.设置变量mathInt为由Z以基数R进行表示的数学进制整数值,其中使用字母A-Za-z表示值为 10 ~ 35 的数字(如果R为 10,且Z包含 20 个以上的有效数字,则根据实现的选择,第 20 位之后的每个有效数字都可以替换为 0)
    ,如果 R 不是 2、4、8、10、16 或 32,则 mathInt 可能是对数学整数值的依赖实现的近似值,该值由 Z 以基数R 表示法表示。
  • 16.如果mathInt等于 0,则:
    • 如果sign等于-1,则返回-0
    • 否则返回+0
  • 17.设置变量numbermathInt的 Number 值;
  • 18.返回sign * number

看起来有点复杂,画了个流程图:
p-rule_parseInt

parseInt() 只能将字符串的前导部分解释为整数值;它忽略任何不能被解释为整数符号的一部分的代码单元,并且没有给出任何此类代码单元被忽略的迹象。

parseFloat()

语法:

parseFloat(string)

其中参数:

  • string:要被解析的值。如果参数不是一个字符串,则将其转换为字符串。标准输入:
    p-parseFloat-input-string

另外:

parseFloat === Number.parseFloat; // => true

ECMAScript(6.0) 规范

官网描述:

p-parseFloat-1

执行步骤:

  • 1.定义变量inputString,它是入参string执行 ToString(string) 的字符串结果。;

  • 2.执行出现异常则返回(ReturnIfAbrupt);

  • 3.定义变量trimmedString,它是inputString创建的一个子字符串,它由第一个不是空白字符的代码单元和该代码单元之后的所有代码单元组成,即去除前置空格,也就是说parseFloat('123.456')parseFloat(' 123.456')效果相同。如果找不到这样的单元,边trimmedString为空字符串("");

  • 4.如果trimmedStringtrimmedString的任何前缀都不满足StrDecimalLiteral的语法,则返回NaN
    StrDecimalLiteral 语法:
    p-strDecimalLiteral.jpg

    文档不是很直观,画了张铁路图:
    p-strDecimalLiteral_rd

  • 5.定义变量numberString,它是trimmedString 的最长前缀(可能是trimmedString) 本身,numberString满足StrDecimalLiteral 的语法。

  • 6.定义变量mathFloat,它是 numberStringMV(mathematical value):从文字中导出MV,其次对这个值进行四舍五入(也有 20 位的阈值处理),这一步处理与parseInt()有很大的不同。至于具体 MV 基本就是大学里学的内容,可见文档;

  • 7.如果mathFloat 等于 0,则:

    • 如果trimmedString的第一个字符等于"-",则返回-0
    • 否则返回+0
  • 8.返回mathFloat的 Number 值;

也画了个流程图:
p-rule_parseFloat

parseFloat() 只能将字符串的前导部分解释为整数值;它忽略任何不能被解释为整数符号的一部分的代码单元,并且没有给出任何此类代码单元被忽略的迹象。

ts

声明文件(lib.es5.d.ts)很简单:

/*** Converts a string to an integer.* @param string A string to convert into a number.* @param radix A value between 2 and 36 that specifies the base of the number in `string`.* If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.* All other strings are considered decimal.*/
declare function parseInt(string: string, radix?: number): number;/*** Converts a string to a floating-point number.* @param string A string that contains a floating-point number.*/
declare function parseFloat(string: string): number;

再次注意NaN也是"number"


内核实现

以典型的WebKit(依赖 v8)为例,可以看下parseInt()parseFloat的具体代码实现和单测内容(版本:tags/9.9.56

parseInt 源码

(主要文件:/Source/JavaScriptCore/runtime/ParseInt.h)

主要代码:

// 入口,方法定义
ALWAYS_INLINE static double parseInt(StringView s, int radix)
{if (s.is8Bit())return parseInt(s, s.characters8(), radix);return parseInt(s, s.characters16(), radix);
}// ES5.1 15.1.2.2
template <typename CharType>
ALWAYS_INLINE
static double parseInt(StringView s, const CharType* data, int radix)
{// 1. Let inputString be ToString(string).// 2. Let S be a newly created substring of inputString consisting of the first character that is not a//    StrWhiteSpaceChar and all characters following that character. (In other words, remove leading white//    space.) If inputString does not contain any such characters, let S be the empty string.int length = s.length();int p = 0;while (p < length && isStrWhiteSpace(data[p]))++p;// 3. Let sign be 1.// 4. If S is not empty and the first character of S is a minus sign -, let sign be -1.// 5. If S is not empty and the first character of S is a plus sign + or a minus sign -, then remove the first character from S.double sign = 1;if (p < length) {if (data[p] == '+')++p;else if (data[p] == '-') {sign = -1;++p;}}// 6. Let R = ToInt32(radix).// 7. Let stripPrefix be true.// 8. If R != 0,then//   b. If R != 16, let stripPrefix be false.// 9. Else, R == 0//   a. LetR = 10.// 10. If stripPrefix is true, then//   a. If the length of S is at least 2 and the first two characters of S are either ―0x or ―0X,//      then remove the first two characters from S and let R = 16.// 11. If S contains any character that is not a radix-R digit, then let Z be the substring of S//     consisting of all characters before the first such character; otherwise, let Z be S.if ((radix == 0 || radix == 16) && length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) {radix = 16;p += 2;} else if (radix == 0)radix = 10;// 8.a If R < 2 or R > 36, then return NaN.if (radix < 2 || radix > 36)return PNaN;// 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters//     A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant//     digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation;//     and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent approximation to the//     mathematical integer value that is represented by Z in radix-R notation.)// 14. Let number be the Number value for mathInt.int firstDigitPosition = p;bool sawDigit = false;double number = 0;while (p < length) {int digit = parseDigit(data[p], radix);if (digit == -1)break;sawDigit = true;number *= radix;number += digit;++p;}// 12. If Z is empty, return NaN.if (!sawDigit)return PNaN;// Alternate code path for certain large numbers.if (number >= mantissaOverflowLowerBound) {if (radix == 10) {size_t parsedLength;number = parseDouble(s.substring(firstDigitPosition, p - firstDigitPosition), parsedLength);} else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)number = parseIntOverflow(s.substring(firstDigitPosition, p - firstDigitPosition), radix);}// 15. Return sign x number.return sign * number;
}

代码中没有“骚”操作,从执行到备注都完全贴合规范。

parseInt unit test

(文件:chromium / v8 / v8 / 9.9.56 / . / test / webkit / parseInt-expected.txt

PASS parseInt('123') is 123
PASS parseInt('123x4') is 123
PASS parseInt('-123') is -123
PASS parseInt('0x123') is 0x123
PASS parseInt('0x123x4') is 0x123
PASS parseInt('-0x123x4') is -0x123
PASS parseInt('-') is Number.NaN
PASS parseInt('0x') is Number.NaN
PASS parseInt('-0x') is Number.NaN
PASS parseInt('123', undefined) is 123
PASS parseInt('123', null) is 123
PASS parseInt('123', 0) is 123
PASS parseInt('123', 10) is 123
PASS parseInt('123', 16) is 0x123
PASS parseInt('0x123', undefined) is 0x123
PASS parseInt('0x123', null) is 0x123
PASS parseInt('0x123', 0) is 0x123
PASS parseInt('0x123', 10) is 0
PASS parseInt('0x123', 16) is 0x123
PASS parseInt(Math.pow(10, 20)) is 100000000000000000000
PASS parseInt(Math.pow(10, 21)) is 1
PASS parseInt(Math.pow(10, -6)) is 0
PASS parseInt(Math.pow(10, -7)) is 1
PASS parseInt(-Math.pow(10, 20)) is -100000000000000000000
PASS parseInt(-Math.pow(10, 21)) is -1
PASS parseInt(-Math.pow(10, -6)) is -0
PASS parseInt(-Math.pow(10, -7)) is -1
PASS parseInt('0') is 0
PASS parseInt('-0') is -0
PASS parseInt(0) is 0
PASS parseInt(-0) is 0
PASS parseInt(2147483647) is 2147483647
PASS parseInt(2147483648) is 2147483648
PASS parseInt('2147483647') is 2147483647
PASS parseInt('2147483648') is 2147483648
PASS state = null; try { parseInt('123', throwingRadix); } catch (e) {} state; is "throwingRadix"
PASS state = null; try { parseInt(throwingString, throwingRadix); } catch (e) {} state; is "throwingString"

parseFloat 源码

(主要文件:/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp)

static double parseFloat(StringView s)
{unsigned size = s.length();if (size == 1) {UChar c = s[0];if (isASCIIDigit(c))return c - '0';return PNaN;}if (s.is8Bit()) {const LChar* data = s.characters8();const LChar* end = data + size;// Skip leading white space.for (; data < end; ++data) {if (!isStrWhiteSpace(*data))break;}// Empty string.if (data == end)return PNaN;return jsStrDecimalLiteral(data, end);}const UChar* data = s.characters16();const UChar* end = data + size;// Skip leading white space.for (; data < end; ++data) {if (!isStrWhiteSpace(*data))break;}// Empty string.if (data == end)return PNaN;return jsStrDecimalLiteral(data, end);
}// See ecma-262 6th 11.8.3
template <typename CharType>
static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
{RELEASE_ASSERT(data < end);size_t parsedLength;double number = parseDouble(data, end - data, parsedLength);if (parsedLength) {data += parsedLength;return number;}// Check for [+-]?Infinityswitch (*data) {case 'I':if (isInfinity(data, end)) {data += SizeOfInfinity;return std::numeric_limits<double>::infinity();}break;case '+':if (isInfinity(data + 1, end)) {data += SizeOfInfinity + 1;return std::numeric_limits<double>::infinity();}break;case '-':if (isInfinity(data + 1, end)) {data += SizeOfInfinity + 1;return -std::numeric_limits<double>::infinity();}break;}// Not a number.return PNaN;
}

相比之下,parseInt的注释要更为完善。

parseFloat test

(文件:chromium / v8 / v8 / 9.9.56 / . / test / webkit / parseFloat-expected.txt

PASS parseFloat() is NaN
PASS parseFloat('') is NaN
PASS parseFloat(' ') is NaN
PASS parseFloat(' 0') is 0
PASS parseFloat('0 ') is 0
PASS parseFloat('x0') is NaN
PASS parseFloat('0x') is 0
PASS parseFloat(' 1') is 1
PASS parseFloat('1 ') is 1
PASS parseFloat('x1') is NaN
PASS parseFloat('1x') is 1
PASS parseFloat(' 2.3') is 2.3
PASS parseFloat('2.3 ') is 2.3
PASS parseFloat('x2.3') is NaN
PASS parseFloat('2.3x') is 2.3
PASS parseFloat('0x2') is 0
PASS parseFloat('1' + nonASCIINonSpaceCharacter) is 1
PASS parseFloat(nonASCIINonSpaceCharacter + '1') is NaN
PASS parseFloat('1' + illegalUTF16Sequence) is 1
PASS parseFloat(illegalUTF16Sequence + '1') is NaN
PASS parseFloat(tab + '1') is 1
PASS parseFloat(nbsp + '1') is 1
PASS parseFloat(ff + '1') is 1
PASS parseFloat(vt + '1') is 1
PASS parseFloat(cr + '1') is 1
PASS parseFloat(lf + '1') is 1
PASS parseFloat(ls + '1') is 1
PASS parseFloat(ps + '1') is 1
PASS parseFloat(oghamSpaceMark + '1') is 1
PASS parseFloat(mongolianVowelSeparator + '1') is NaN
PASS parseFloat(enQuad + '1') is 1
PASS parseFloat(emQuad + '1') is 1
PASS parseFloat(enSpace + '1') is 1
PASS parseFloat(emSpace + '1') is 1
PASS parseFloat(threePerEmSpace + '1') is 1
PASS parseFloat(fourPerEmSpace + '1') is 1
PASS parseFloat(sixPerEmSpace + '1') is 1
PASS parseFloat(figureSpace + '1') is 1
PASS parseFloat(punctuationSpace + '1') is 1
PASS parseFloat(thinSpace + '1') is 1
PASS parseFloat(hairSpace + '1') is 1
PASS parseFloat(narrowNoBreakSpace + '1') is 1
PASS parseFloat(mediumMathematicalSpace + '1') is 1
PASS parseFloat(ideographicSpace + '1') is 1

最后

从 ECMA 规范和典型内核的代码实现中我们可以发现,parseFloatparseInt存在很多边界处理,这也是造成踩坑的主要原因。

至此可以再回过头想想最初的那些执行问题,绝大部分都能得到解释。至于“超纲”题,有兴趣可以去看下 ECMA 规范中的数字及类型转换部分。


附录

tostring

p-table12-tostring

MV(mathematical value)

p-mv

parseFloat input string 格式

Diagram(ZeroOrMore('Space'),Optional(Choice(0,'+','-',), 'skip'),Choice(1,'Infinity',Sequence(Choice(0,Sequence(ZeroOrMore('0-9'),Optional('.', 'skip'),OneOrMore('0-9'),),),Optional(Sequence(Choice(0,'e','E',),Optional(Choice(0,'+','-',), 'skip'),OneOrMore('0-9'),), 'skip'))),ZeroOrMore('Space'),
)

parseInt input string 格式

Diagram(ZeroOrMore('Space'),Optional(Choice(0,'+','-',), 'skip'),ZeroOrMore('0-R'),	// R 为进制最大值ZeroOrMore('Space'),
)

有建议或转载可 -> michealwayne@163.com

相关链接

  • https://262.ecma-international.org/6.0/
  • https://262.ecma-international.org/6.0/#sec-tostring-applied-to-the-number-type
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat
  • https://webkit.org/
  • https://github.com/WebKit/WebKit
  • https://github.com/MichealWayne/study-js-from-questions/blob/master/1.1%20MemoryHeap.md

http://chatgpt.dhexx.cn/article/JuD9ZHki.shtml

相关文章

python实现简单的聊天小程序

概要 这是一个使用python实现一个简单的聊天室的功能,里面包含群聊,私聊两种聊天方式.实现的方式是使用套接字编程的一个使用TCP协议 c/s结构的聊天室 实现思路 x01 服务端的建立 首先,在服务端,使用socket进行消息的接受,每接受一个socket的请求,就开启一个新的线程来管理…

微信小程序调出选择好友聊天窗口

微信小程序分享好友 点击分享&#xff0c;弹出层选择“分享给微信好友”&#xff0c;点击‘“分享给微信好友”&#xff0c;直接调出选择好友聊天窗口。 如图&#xff1a; 微信小程序API&#xff1a;onShareAppMessage 定义 onShareAppMessage 函数&#xff0c;设置该页面的…

小程序mqtt实现聊天功能

mqtt是什么&#xff1f; MQTT是一个轻量级传输协议&#xff0c;它被设计用于轻量级的发布/订阅式消息传输&#xff0c;MQTT协议针对低带宽网络&#xff0c;低计算能力的设备&#xff0c;做了特殊的优化。是一种简单、稳定、开放、轻量级易于实现的消息协议&#xff0c;在物联网…

微信小程序接入腾讯IM即时通讯,实现在线聊天

最近在帮朋友写一个二手交易平台&#xff0c;买卖双方在线沟通的功能(类似于某鱼&#xff09; 先上传做完的效果图&#xff0c;后续再更新源码&#xff0c;目前实现了消息列表显示未读数量&#xff0c;显示最后一条信息内容&#xff0c;收到信息后刷新列表。聊天页面 不要吐槽…

应用实战|微信小程序开发示例--多人聊天互动空间

“超能力”数据库&#xff5e;拿来即用&#xff0c;应用开发人员再也不用为撰写API而发愁。MemFire Cloud 为开发者提供了简单易用的云数据库&#xff08;表编辑器、自动生成API、SQL编辑器、备份恢复、托管运维&#xff09;&#xff0c;很大地降低开发者的使用门槛。 本示例是…

微信小程序实现websocket及单人聊天功能

一、什么是websocket&#xff1a; WebSocket是HTML5下一种新的协议&#xff08;websocket协议本质上是一个基于tcp的协议&#xff09;它实现了浏览器与服务器全双工通信&#xff0c;能更好的节省服务器资源和带宽并达到实时通讯的目的Websocket是一个持久化的协议 二、websoc…

uni-app+websocket实现语音聊天小程序

uni-appwebsocket 开发语音聊天咨询小程序

微信小程序中百分百实现聊天界面

众所周知,全网来看,微信的聊天界面看着就是舒服,那能否在微信小程序中实现该功能,同时可以实现输入文本和语音功能,而且在输入文本时,键盘可以弹起。话不多说,上界面看看。 wxml实现如下: <view> <scroll-view scroll-y scroll-into-view={{toView}} style=h…

图灵聊天机器人小程序

历时半年整理出了十多万字的学习笔记&#xff0c;目前依旧在更新 欢迎点赞和支持&#xff5e;&#x1f973;&#x1f973;&#x1f973; 博客 项目描述&#xff1a; 根据图灵API向聊天机器人发送聊天信息&#xff0c;并渲染返回的数据。具有清空聊天记录的按钮。本来是想上线…

微信小程序-模仿绘制聊天界面

参考文章 1、小程序模仿微信聊天界面 2、微信小程序实现仿微信聊天界面(各种细节处理) 3、微信小程序之页面中关于聊天框三角形的制作和使用 4、仿微信聊天记录时间显示 5、微信小程序-同时获取麦克风、相机权限、获取多个权限 6、【uni-app】模仿微信实现简易发送/取发语音功…

微信聊天小程序——(二、账号的注册与登录)

具体效果&#xff1a; 目录 二、账号的注册与登录 步骤一、获取用户信息 步骤二、用户输入账号密码&#xff08;在注册页面中&#xff09; 步骤三、将获取到的值放到我们的数据库中&#xff08;在注册页面中&#xff09; 步骤四、登录的页面逻辑 步骤五、登录页面的实现 …

微信聊天小程序——(三、获取好友列表)

三、获取好友列表 步骤一、展示所有好友的推荐列表&#xff08;friends页面&#xff09; 具体效果&#xff1a; 实现思路&#xff1a; 我们有我们的用户数据库表即&#xff1a;uers循环我们的数据库用户表&#xff0c;达到所有的用户信息&#xff0c;即&#xff1a;userLi…

微信聊天小程序——(五、添加好友)

五、添加好友 步骤一、通过搜索添加好友 具体效果&#xff1a; 思路&#xff1a; 本质上来讲&#xff0c;就是通过输入框得到好友账号信息&#xff0c;之后再数据库中查询&#xff0c;最后返回并渲染查询结果。首先&#xff0c;得到输入框的值&#xff0c;并传递到我们的页面…

支付宝小程序平台的IM聊天插件

文章目录 前言一、用户端1.基本展示2.难处理的点二、另一用户端1.前端websocket的整合2.手机息屏websocket断线问题2.websocket服务端配置3.后端整合websocket作为服务端&#xff0c;传输消息给前端 总结 前言 最近工作需求来了个项目&#xff0c;前景为在支付宝平台上发布一个…

使用 Python 编写一个聊天小程序

欢迎关注 “小白玩转Python”&#xff0c;发现更多 “有趣” 本篇文章分享如何用相当简洁的 Python 代码制作一个简单的聊天应用程序。更重要的是&#xff0c;我已经实现了没有任何第三方依赖的代码&#xff01; 首先&#xff0c;我创建了一个聊天服务器&#xff0c;通过它可以…

小米手机解BL锁教程

1.找到设置&#xff0c;找到我的设备 2.点击全部参数&#xff0c;多点几下miui版本&#xff0c;直到弹出开发者模式提醒。 3.返回&#xff0c;找到更多设置 4.找到开发者选项 5.找到设备定状态 6.绑定账号和设备&#xff0c;关机&#xff0c;按开键加音量减&#xff0c;进去fas…

安卓搞机玩机-什么是“锁 ” BL锁 屏幕锁 账号锁 设备锁等分析

相信把玩安卓机型的友友们都大概了解机型的锁是什么概念。但有些友友可能还分不清楚具体锁的概念。今天这个帖子由浅入深的带你了解安卓机型中各种“锁”的概念.这类话题比较敏感。只是大概带你分清楚锁的分类和基本对应的解锁方式. 一.屏幕锁【 图案锁 指纹锁 数字锁 人…

万能小米手机解锁,刷机,默认破解BL锁

写在第一条:下载之前请注意 本软件不支持最新机型,只支持4代和4代以前的机型,请注意 早就想给自己的小米手机刷机了&#xff0c;奈何一直没有门&#xff0c;最后还在求助了万能的淘宝&#xff0c;刚刚在淘宝花了 30大洋买的刷机工具&#xff0c;刷机成功之后&#xff0c;才反…

xiaomi 小米 红米redmi 秒解锁BL锁,不用等,在线秒解锁BL工具介绍

xiaomi 小米 红米redmi 秒解锁BL锁,不用等&#xff0c;在线秒解锁BL Xlaomi Redmi K40 Gaming Xlaomt Poco F3 GT Gaming Xaoml Poco X3 GT Xaoml Redmi Note9 5G Xlaomi Redml Note 10 Pro 5G Xlaoml Redmi Note 10 5G Xlaoml Redml Note 10T 5G Xlaoml Poco M3 Pro 5G Xaoml…

小米手机解BL锁、线刷详细教程,适用于小米全系列手机

[教程] 小米手机解BL锁、线刷详细教程&#xff0c;适用于小米全系列手机 这几天看到论坛里很多人在问怎么线刷&#xff0c;下面我就做个详细的线教程大家看一下高手别喷我哈 此教程只适合刷官方MIUI包 进入正题。 第一步&#xff1a;解BL锁 1.浏览器打开申请解锁小米手机点击立…