JavaScript 只有一種數(shù)字類型。
可以使用也可以不使用小數(shù)點來書寫數(shù)字。
JavaScript 數(shù)字可以使用也可以不使用小數(shù)點來書寫:
var pi=3.14; // 使用小數(shù)點
var x=34; // 不使用小數(shù)點
極大或極小的數(shù)字可通過科學(指數(shù))計數(shù)法來寫:
var y=123e5; // 12300000
var z=123e-5; // 0.00123
JavaScript 不是類型語言。與許多其他編程語言不同,JavaScript 不定義不同類型的數(shù)字,比如整數(shù)、短、長、浮點等等。
JavaScript 中的所有數(shù)字都存儲為根為 10 的 64 位(8 比特),浮點數(shù)。
整數(shù)(不使用小數(shù)點或指數(shù)計數(shù)法)最多為 15 位。
小數(shù)的最大位數(shù)是 17,但是浮點運算并不總是 100% 準確:
var x=0.2+0.1;
如果前綴為 0,則 JavaScript 會把數(shù)值常量解釋為八進制數(shù),如果前綴為 0 和 "x",則解釋為十六進制數(shù)。
var y=0377;
var z=0xFF;
提示:絕不要在數(shù)字前面寫零,除非您需要進行八進制轉換。
我建了一個【前端學習群】,【免費領取學習資料】或?qū)W習的同學可以關注我:前端學習交流 - 知乎
、新建項目
1、新建===web項目===輸入項目名稱====完成
二、新建html文件
在新建項目中新建html模板
輸入文件名稱:
三、認識基本格式
聯(lián)想出基本格式:
四、編輯html文件
運行html,選擇瀏覽器
五、html常用的快捷鍵
(1)ctrl+n+w web項目創(chuàng)建
(2)ctrl+n+h html文檔創(chuàng)建
(3)ctrl+s 保存html頁面(頁面上如果未保存會顯示*號)
(4)ctrl+r html運行
(5)ctrl+z 撤回
(6)!+tab鍵 聯(lián)想基本格式
(7)ctrl+/ 注釋和取消注釋
(8)ctrl+鼠標滾輪, 字體方大和縮小
六、認識標簽
(1)H標簽(標題標簽)
(2)p標簽 (段落標簽)
(3)img 標簽(圖片標簽)
兩種:第一種widows上傳圖片,第二種:網(wǎng)上圖片鏈接
第一種
img中顯示圖片
img中引入圖片
第二種:網(wǎng)上圖片的鏈接:
(4) 標簽(空格)
(5)em 標簽表示斜體
(6)i 標簽表示斜體
(7)br 表示換行
(8)b 標簽表示加粗
(9) strong 標簽表示加粗
(10)s 標簽(刪除線)
(11)u 標簽 (下劃線)
(12)font 顏色
(13)sub下標
(14)sup上標
.訂單號生成的原則:
1.全局的唯一性
2.自增長
3.長度的要求
4.具有一定的可讀性
5.保密,不可推測性
6.效率性
二.實現(xiàn)方案
常見的ID生成策略。 1. 數(shù)據(jù)庫自增長序列或字段 2. UUID 3. UUID的變種*【UUID to Int64;NHibernate在其主鍵生成方式中提供了Comb算法(combined guid/timestamp)】 4. Redis生成ID 5. Twitter的snowflake算法 6. 利用zookeeper的znode生成唯一ID 7. MongoDB的ObjectId
三.高并發(fā)下怎樣生成唯一的訂單號?
如果沒有并發(fā),訂單號只在一個線程內(nèi)產(chǎn)生,那么由于程序是順序執(zhí)行的,不同訂單的生成時間一定不同,因此用時間就可以區(qū)分各個訂單。
如果存在并發(fā),且訂單號是由一個進程中的多個線程產(chǎn)生的,那么只要把線程ID添加到序列號中就可以保證訂單號唯一。
如果存在并發(fā),且訂單號是由同一臺主機中的多個進程產(chǎn)生的,那么只要把進程ID添加到序列號中就可以保證訂單號唯一。
如果存在并發(fā),且訂單號是由不同臺主機產(chǎn)生的,那么MAC地址、IP地址或CPU序列號等能夠區(qū)分主機的號碼添加到序列號中就可以保證訂單號唯一。
1. 機器碼(3位, 分布式節(jié)點),年月日分時秒(12位),遞增的序列(4位),當并發(fā)遞增序列超過4位時,秒數(shù)+1,序列從0開始計時,這樣每秒支持9999個訂單號生成,隔天序列清為0.
2.后臺統(tǒng)一生成的訂單號后,推入redis,一次性推個幾十W個,檢查剩余多少后,再推,也可以保證高并發(fā)的場景。
四.Twitter開源分布式自增ID算法snowflake
1.snowflake簡介
互聯(lián)網(wǎng)快速發(fā)展的今天,分布式應用系統(tǒng)已經(jīng)見怪不怪,在分布式系統(tǒng)中,我們需要各種各樣的ID,既然是ID那么必然是要保證全局唯一,除此之外,不同當業(yè)務還需要不同的特性,比如像并發(fā)巨大的業(yè)務要求ID生成效率高,吞吐大;比如某些銀行類業(yè)務,需要按每日日期制定交易流水號;又比如我們希望用戶的ID是隨機的,無序的,純數(shù)字的,且位數(shù)長度是小于10位的。等等,不同的業(yè)務場景需要的ID特性各不一樣,于是,衍生了各種ID生成器,但大多數(shù)利用數(shù)據(jù)庫控制ID的生成,性能受數(shù)據(jù)庫并發(fā)能力限制,那么有沒有一款不需要依賴任何中間件(如數(shù)據(jù)庫,分布式緩存服務等)的ID生成器呢?本著取之于開源,用之于開源的原則,今天,特此介紹Twitter開源的一款分布式自增ID算法snowflake,并附上算法原理推導和演算過程!
snowflake算法是一款本地生成的(ID生成過程不依賴任何中間件,無網(wǎng)絡通信),保證ID全局唯一,并且ID總體有序遞增,性能每秒生成300w+。
2.snowflake算法原理
snowflake生產(chǎn)的ID是一個18位的long型數(shù)字,二進制結構表示如下(每部分用-分開):
0 - 00000000 00000000 00000000 00000000 00000000 0 - 00000 - 00000 - 00000000 0000
第一位未使用,接下來的41位為毫秒級時間(41位的長度可以使用69年,從1970-01-01 08:00:00),然后是5位datacenterId(最大支持2^5=32個,二進制表示從00000-11111,也即是十進制0-31),和5位workerId(最大支持2^5=32個,原理同datacenterId),所以datacenterId*workerId最多支持部署1024個節(jié)點,最后12位是毫秒內(nèi)的計數(shù)(12位的計數(shù)順序號支持每個節(jié)點每毫秒產(chǎn)生2^12=4096個ID序號).
所有位數(shù)加起來共64位,恰好是一個Long型(轉換為字符串長度為18).
單臺機器實例,通過時間戳保證前41位是唯一的,分布式系統(tǒng)多臺機器實例下,通過對每個機器實例分配不同的datacenterId和workerId避免中間的10位碰撞。最后12位每毫秒從0遞增生產(chǎn)ID,再提一次:每毫秒最多生成4096個ID,每秒可達4096000個。理論上,只要CPU計算能力足夠,單機每秒可生產(chǎn)400多萬個,實測300w+,效率之高由此可見。
(該節(jié)改編自:http://www.cnblogs.com/relucent/p/4955340.html)
3.snowflake算法源碼(java版)
@ToString
@Slf4j
public class SnowflakeIdFactory {
private final long twepoch=1288834974657L;
private final long workerIdBits=5L;
private final long datacenterIdBits=5L;
private final long maxWorkerId=-1L ^ (-1L << workerIdBits);
private final long maxDatacenterId=-1L ^ (-1L << datacenterIdBits);
private final long sequenceBits=12L;
private final long workerIdShift=sequenceBits;
private final long datacenterIdShift=sequenceBits + workerIdBits;
private final long timestampLeftShift=sequenceBits + workerIdBits + datacenterIdBits;
private final long sequenceMask=-1L ^ (-1L << sequenceBits);
private long workerId;
private long datacenterId;
private long sequence=0L;
private long lastTimestamp=-1L;
public SnowflakeIdFactory(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId=workerId;
this.datacenterId=datacenterId;
}
public synchronized long nextId() {
long timestamp=timeGen();
if (timestamp < lastTimestamp) {
//服務器時鐘被調(diào)整了,ID生成器停止服務.
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp==timestamp) {
sequence=(sequence + 1) & sequenceMask;
if (sequence==0) {
timestamp=tilNextMillis(lastTimestamp);
}
} else {
sequence=0L;
}
lastTimestamp=timestamp;
return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
}
protected long tilNextMillis(long lastTimestamp) {
long timestamp=timeGen();
while (timestamp <=lastTimestamp) {
timestamp=timeGen();
}
return timestamp;
}
protected long timeGen() {
return System.currentTimeMillis();
}
public static void testProductIdByMoreThread(int dataCenterId, int workerId, int n) throws InterruptedException {
List<Thread> tlist=new ArrayList<>();
Set<Long> setAll=new HashSet<>();
CountDownLatch cdLatch=new CountDownLatch(10);
long start=System.currentTimeMillis();
int threadNo=dataCenterId;
Map<String,SnowflakeIdFactory> idFactories=new HashMap<>();
for(int i=0;i<10;i++){
//用線程名稱做map key.
idFactories.put("snowflake"+i,new SnowflakeIdFactory(workerId, threadNo++));
}
for(int i=0;i<10;i++){
Thread temp=new Thread(new Runnable() {
@Override
public void run() {
Set<Long> setId=new HashSet<>();
SnowflakeIdFactory idWorker=idFactories.get(Thread.currentThread().getName());
for(int j=0;j<n;j++){
setId.add(idWorker.nextId());
}
synchronized (setAll){
setAll.addAll(setId);
log.info("{}生產(chǎn)了{}個id,并成功加入到setAll中.",Thread.currentThread().getName(),n);
}
cdLatch.countDown();
}
},"snowflake"+i);
tlist.add(temp);
}
for(int j=0;j<10;j++){
tlist.get(j).start();
}
cdLatch.await();
long end1=System.currentTimeMillis() - start;
log.info("共耗時:{}毫秒,預期應該生產(chǎn){}個id, 實際合并總計生成ID個數(shù):{}",end1,10*n,setAll.size());
}
public static void testProductId(int dataCenterId, int workerId, int n){
SnowflakeIdFactory idWorker=new SnowflakeIdFactory(workerId, dataCenterId);
SnowflakeIdFactory idWorker2=new SnowflakeIdFactory(workerId+1, dataCenterId);
Set<Long> setOne=new HashSet<>();
Set<Long> setTow=new HashSet<>();
long start=System.currentTimeMillis();
for (int i=0; i < n; i++) {
setOne.add(idWorker.nextId());//加入set
}
long end1=System.currentTimeMillis() - start;
log.info("第一批ID預計生成{}個,實際生成{}個<<<<*>>>>共耗時:{}",n,setOne.size(),end1);
for (int i=0; i < n; i++) {
setTow.add(idWorker2.nextId());//加入set
}
long end2=System.currentTimeMillis() - start;
log.info("第二批ID預計生成{}個,實際生成{}個<<<<*>>>>共耗時:{}",n,setTow.size(),end2);
setOne.addAll(setTow);
log.info("合并總計生成ID個數(shù):{}",setOne.size());
}
public static void testPerSecondProductIdNums(){
SnowflakeIdFactory idWorker=new SnowflakeIdFactory(1, 2);
long start=System.currentTimeMillis();
int count=0;
for (int i=0; System.currentTimeMillis()-start<1000; i++,count=i) {
/** 測試方法一: 此用法純粹的生產(chǎn)ID,每秒生產(chǎn)ID個數(shù)為300w+ */
idWorker.nextId();
/** 測試方法二: 在log中打印,同時獲取ID,此用法生產(chǎn)ID的能力受限于log.error()的吞吐能力.
* 每秒徘徊在10萬左右. */
//log.error("{}",idWorker.nextId());
}
long end=System.currentTimeMillis()-start;
System.out.println(end);
System.out.println(count);
}
public static void main(String[] args) {
/** case1: 測試每秒生產(chǎn)id個數(shù)?
* 結論: 每秒生產(chǎn)id個數(shù)300w+ */
//testPerSecondProductIdNums();
/** case2: 單線程-測試多個生產(chǎn)者同時生產(chǎn)N個id,驗證id是否有重復?
* 結論: 驗證通過,沒有重復. */
//testProductId(1,2,10000);//驗證通過!
//testProductId(1,2,20000);//驗證通過!
/** case3: 多線程-測試多個生產(chǎn)者同時生產(chǎn)N個id, 全部id在全局范圍內(nèi)是否會重復?
* 結論: 驗證通過,沒有重復. */
try {
testProductIdByMoreThread(1,2,100000);//單機測試此場景,性能損失至少折半!
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
測試用例
/** case1: 測試每秒生產(chǎn)id個數(shù)?
* 結論: 每秒生產(chǎn)id個數(shù)300w+ */
//testPerSecondProductIdNums();
/** case2: 單線程-測試多個生產(chǎn)者同時生產(chǎn)N個id,驗證id是否有重復?
* 結論: 驗證通過,沒有重復. */
//testProductId(1,2,10000);//驗證通過!
//testProductId(1,2,20000);//驗證通過!
/** case3: 多線程-測試多個生產(chǎn)者同時生產(chǎn)N個id, 全部id在全局范圍內(nèi)是否會重復?
* 結論: 驗證通過,沒有重復. */
try {
testProductIdByMoreThread(1,2,100000);//單機測試此場景,性能損失至少折半!
} catch (InterruptedException e) {
e.printStackTrace();
}
4.snowflake算法推導和演算過程
說明:
演算使用的對象實例:SnowflakeIdFactory idWorker=new SnowflakeIdFactory(1, 2);
運行時數(shù)據(jù)workerId=1,datacenterId=2,分別表示機器實例的生產(chǎn)者編號,數(shù)據(jù)中心編號;
sequence=0表示每毫秒生產(chǎn)ID從0開始計數(shù)遞增;
以下演算基于時間戳=1482394743339時刻進行推導。
一句話描述:以下演算模擬了1482394743339這一毫秒時刻,workerId=1,datacenterId=2的id生成器,生產(chǎn)第一個id的過程。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。