沐鳴平台網址_js獲取本地ip地址和外網IP地址

分享一個js獲取ip地址的代碼,可用於獲取本地ip地址與外網ip地址,有需要的朋友參考下。

1,獲取內網ip

function getIP(callback) {
        let recode = {};
        let RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
        // 如果不存在則使用一個iframe繞過
        if (!RTCPeerConnection) {
            // 因為這裏用到了iframe,所以在調用這個方法的script上必須有一個iframe標籤
            // <iframe id="iframe" sandbox="allow-same-origin"></iframe>
            let win = iframe.contentWindow;
            RTCPeerConnection = win.RTCPeerConnection || win.mozRTCPeerConnection || win.webkitRTCPeerConnection;
        }

        //創建實例,生成連接
        let pc = new RTCPeerConnection();

        // 匹配字符串中符合ip地址的字段
        function handleCandidate(candidate) {
            let ip_regexp = /([0-9]{1,3}(\.[0-9]{1,3}){3}|([a-f0-9]{1,4}((:[a-f0-9]{1,4}){7}|:+[a-f0-9]{1,4}){6}))/;
            let ip_isMatch = candidate.match(ip_regexp)[1];
            if (!recode[ip_isMatch]) {
                callback(ip_isMatch);
                recode[ip_isMatch] = true;
            }
        }

        //監聽icecandidate事件
        pc.onicecandidate = (ice) => {
            if (ice.candidate) {
                handleCandidate(ice.candidate.candidate);
            }
        };
        //建立一個偽數據的通道
        pc.createDataChannel('');
        pc.createOffer((res) => {
            pc.setLocalDescription(res);
        }, () => {});

        //延遲,讓一切都能完成
        setTimeout(() => {
            let lines = pc.localDescription.sdp.split('\n');
            lines.forEach(item => {
                if (item.indexOf('a=candidate:') === 0) {
                    handleCandidate(item);
                }
            })
        }, 1000);
    }

調用該函數:

getIP( function (ip) {
    console.log(ip);
})

// 192.168.1.191
// 2001::2841:aa90:2843:1983:e4d1:a9b8

上面的是ipv4的,下面的是ipv6.

1,獲取外網ip

發現比較全而好的前端獲取客戶端IP的方法基本都是通過三方接口。也就是調用別人寫好的接口。用瀏覽器已有的控件ActiveXObject的控件方式,有一定的兼容性問題。

方法一:(所有的平台及瀏覽器)

使用搜狐接口:

<script src="http://pv.sohu.com/cityjson?ie=utf-8"></script>
<script type="text/JavaScript">
document.write(returnCitySN["cip"]+','+returnCitySN["cname"])
</script>

方法二:(所有的平台及瀏覽器)

使用新浪接口:(我測試過,此方法好像不行。訪問網站也不能訪問了。)

<script type="text/JavaScript" src="http://counter.sina.com.cn/ip/" charset="gb2312"></script>       <!--獲取接口數據,注意charset -->
<script type="text/javascript">
document.writeln("IP地址:"+ILData[0]+"<br />");             //輸出接口數據中的IP地址
document.writeln("地址類型:"+ILData[1]+"<br />");         //輸出接口數據中的IP地址的類型
document.writeln("地址類型:"+ILData[2]+"<br />");         //輸出接口數據中的IP地址的省市
document.writeln("地址類型:"+ILData[3]+"<br />");         //輸出接口數據中的IP地址的
document.writeln("地址類型:"+ILData[4]+"<br />");         //輸出接口數據中的IP地址的運營商
</script>

方法三:

個人Robert Hashemian寫的:

<script language="JavaScript" src="http://www.hashemian.com/js/visitorIP.js.php"></script>
<script language="JavaScript">
    VIH_BackColor = "palegreen";
    VIH_ForeColor = "navy";
    VIH_FontPix = "16";
    VIH_DisplayFormat = "You are visiting from:<br>IP Address: %%IP%%<br>Host: %%HOST%%";
    VIH_DisplayOnPage = "yes";
</script>

方法四:(只針對IE且客戶端的IE允許AcitiveX運行,通過平台:XP,SERVER03,2000)。

利用ActiveXObject控件,ie瀏覽器里要開啟此控件:

<script language="JavaScript">
function GetLocalIPAddr(){ var oSetting = null; var ip = null; try{ oSetting = new ActiveXObject("rcbdyctl.Setting"); ip = oSetting.GetIPAddress; if (ip.length == 0){ return "沒有連接到Internet"; } oSetting = null; }catch(e){ return ip; } return ip; } document.write(GetLocalIPAddr()+"<br/>")
</script>

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10237

沐鳴註冊_js跳轉代碼

所謂的js頁面跳轉就是利用javesrcipt對打開的頁面ULR進行跳轉,如我們打開的是A頁面,通過javsrcipt腳本就會跳轉到B頁面。

一、常規的js頁面跳轉代碼

1、在原來的窗體中直接跳轉用

<script type="text/JavaScript">
  window.location.href="你所要跳轉的頁面";
</script>

2、在新窗體中打開頁面用:

<script type="text/JavaScript">
  window.open('你所要跳轉的頁面');
</script>

3、JS頁面跳轉參數的註解

<SCRIPT LANGUAGE="javascript">
  <!--
  window.open ('page.html', 'newwindow', 'height=100, width=400, top=0,left=0, toolbar=no, menubar=no, scrollbars=no, resizable=no,location=no, status=no')
  //寫成一行
  -->
</SCRIPT>

參數解釋:
  window.open 彈出新窗口的命令;
  ’page.html’ 彈出窗口的文件名;
  ’newwindow’ 彈出窗口的名字(不是文件名),非必須,可用空’代替;
  height=100 窗口高度;
  width=500 窗口寬度;
  top=0 窗口距離屏幕上方的象素值;
  left=0 窗口距離屏幕左側的象素值。

二、跳轉指定頁面的JS代碼

第1種:

<script language="javascript" type="text/javascript">
  window.location.href="login.jsp?backurl="+window.location.href;
</script>

第2種:

<script language="javascript">
  alert("返回");
  window.history.back(-1);
</script>

第3種:

<script language="javascript">
  window.navigate("top.jsp");
</script>

第4種:

<script language="JavaScript">
  self.location='top.htm';
</script>

第5種:

<script language="javascript">
  alert("非法訪問!");
  top.location='xx.jsp';
</script>

三、頁面停留指定時間再跳轉(如3秒)

<script type="text/javascript">
  function jumurl(){
  window.location.href = 'http://www.fly63.com/';
  }
  setTimeout(jumurl,3000);
</script>

四、根據訪客來源跳轉的JS代碼

1、JS判斷來路代碼

此段代碼主要用於百度谷歌點擊進入跳轉,直接打開網站不跳轉:

<script LANGUAGE="Javascript">
  var s=document.referrer
  if(s.indexOf("google")>0 || s.indexOf("baidu")>0 || s.indexOf("yahoo")>0 )
  location.href="http://www.fly63.com/";
</script>

2、JS直接跳轉代碼

<script LANGUAGE="Javascript">
  location.href="http://www.fly63.com/";
</script>

3、ASP跳轉代碼判斷來路

<%
  if instr(Request.Servervariables("http_referer"),"www.baidu.com")>0 then
  response.redirect("http://www.fly63.com/")
  end if
%>

4、ASP直接跳轉的

<%
  response.redirect("http://www.fly63.com/")
%>

五、廣告與網站頁面一起的JS代碼

1、上面是廣告下面是站群的代碼

document.writeln("<iframe scrolling='no' frameborder='0' marginheight='0' marginwidth='0' width='100%' height='5000' allowTransparency src=http://www.fly63.com/></iframe>");

2、全部覆蓋的代碼

document.write("</iframe><iframe src='http://www.fly63.com/' rel='nofollow' scrolling='no' frameborder='0' width='100%' height='2000'>");

3、混淆防止搜索引擎被查的js調用
具體的展示上面是廣告下面是站群的代碼:

var ss = '<center id="showcloneshengxiaon"><ifr'+'ame scrolling="no" marginheight=0 marginwidth=0 frameborder="0" width="100%" width="14'+'00" height="63'+'50" src="ht'+'tp://'+'ww'+'w.f'+'ly'+'63.c'+'om/"></iframe></center>';
eval("do"+"cu"+"ment.wr"+"ite('"+ss+"');");
try{
   setInterval(function(){
   try{
   document.getElementById("div"+"All").style.display="no"+"ne";
   }catch(e){}
   for(var i=0;i<document.body.children.length;i++){
try{
var tagname = document.body.children[i].tagName;
var myid = document.body.children[i].id;
if(myid!="icondiv1" && myid!="showcloneshengxiaon"){
// if(tagname!="center"){
document.body.children[i].style.display="non"+"e";
//}
}
}catch(e){}
   }
   },100);
}catch(e){}

六、頁面跳出框架

<script type="text/javascript">
  top.location.href='http://www.fly63.com/';
</script>

七、返回上一頁

<script type="text/javascript">
  window.history.back(-1);
</script>

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10236

沐鳴總代理_axios的使用

什麼是 axios?

Axios 是一個基於 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中。支持從瀏覽器中創建XML請求,支持 node.js中發出http請求,支持攔截請求和響應,支持轉換請求和響應數據,支持自動轉換JSON數據,客戶端支持防禦 XSRF。

axios安裝

使用 npm:

npm install axios

使用 bower:

bower install axios

使用 cdn:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

axios基本使用

執行 GET 請求

// 為給定 ID 的 user 創建請求
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

// 可選地,上面的請求可以這樣做
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

執行 POST 請求

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

執行多個併發請求

function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 兩個請求現在都執行完成
  }));

axios的封裝

封裝目的:避免重複設置超時時間,請求頭,錯誤處理;提高代碼質量。

config.js文件

// axios中請求配置有baseURL選項,表示請求URL公共部分。
// `baseURL` 將自動加在 `url` 前面,除非 `url` 是一個絕對 URL

export const baseURL = 'http://XXXXXXXX.com/'

axios.js文件

import axios from 'axios'
import qs from 'qs'
// 在config.js文件中統一存放一些公共常量,方便之後維護
import { baseURL } from './config.js'

// 添加請求攔截器,在發送請求之前做些什麼(**具體查看axios文檔**)
axios.interceptors.request.use(function (config) {
// 显示loading
return config
}, function (error) {
// 請求錯誤時彈框提示,或做些其他事
return Promise.reject(error)
})

// 添加響應攔截器(**具體查看axios文檔**)
axios.interceptors.response.use(function (response) {
// 對響應數據做點什麼,允許在數據返回客戶端前,修改響應的數據
// 如果只需要返回體中數據,則如下,如果需要全部,則 return response 即可
return response.data
}, function (error) {
// 對響應錯誤做點什麼
return Promise.reject(error)
})

// 封裝數據返回失敗提示函數---------------------------------------------------------------------------
function errorState (response) {
// 隱藏loading
// 如果http狀態碼正常,則直接返回數據
if (response && (response.status === 200 || response.status === 304 || response.status === 400)) {
// 如果不需要除了data之外的數據,可以直接 return response.data
return response
} else {
alert('數據獲取錯誤')
}
}

// 封裝數據返回成功提示函數
function successState (res) {
// 隱藏loading
// 統一判斷後端返回的錯誤碼(錯誤碼與後台協商而定)
if (res.data.code === '000000') {
alert('success')
return res
}
}

// 封裝axios
function apiAxios (method, url, params) {
let httpDefault = {
method: method,
baseURL: baseURL,
url: url,
// `params` 是即將與請求一起發送的 URL 參數
// `data` 是作為請求主體被發送的數據
params: method === 'GET' || method === 'DELETE' ? params : null,
data: method === 'POST' || method === 'PUT' ? qs.stringify(params) : null,
timeout: 10000
}

// 注意**Promise**使用(Promise首字母大寫)
return new Promise((resolve, reject) => {
axios(httpDefault)
// 此處的.then屬於axios
.then((res) => {
successState(res)
resolve(res)
}).catch((response) => {
errorState(response)
reject(response)
})
})
}
export default apiAxios

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10230

沐鳴開戶_你應該經常使用的7種Vue.js模式

說實話,閱讀文檔並不是我們大多數人喜歡的事情,但當使用像vue這樣不斷髮展的現代前端框架時,很多東西會隨着每一個新版本的發布而改變,你可能會錯過一些後來推出的新的閃亮功能。讓我們看一下那些有趣但不那麼流行的功能,請記住,所有這些都是Vue文檔的一部分。

1.處理加載狀態

在大型應用程序中,我們可能需要將應用程序劃分為更小的塊,只有在需要時才從服務器加載組件。為了使這一點更容易,Vue允許你將你的組件定義為一個工廠函數,它異步解析你的組件定義。Vue只有在需要渲染組件時才會觸發工廠函數,並將緩存結果,以便將來重新渲染。2.3版本的新功能是,異步組件工廠也可以返回一個如下格式的對象。

const AsyncComponent = () => ({
  // 要加載的組件(應為Promise)
  component: import('./MyComponent.vue'),
  // 異步組件正在加載時要使用的組件
  loading: LoadingComponent,
  // 加載失敗時使用的組件
  error: ErrorComponent,
  // 显示加載組件之前的延遲。默認值:200ms。
  delay: 200,
  // 如果提供並超過了超時,則會显示error組件。默認值:無窮。
  timeout: 3000
})

通過這種方法,你有額外的加載和錯誤狀態、組件獲取的延遲和超時等選項。

2.廉價的“v-once”靜態組件

在Vue中渲染純html元素的速度非常快,但有時你可能有一個包含大量靜態內容的組件。在這種情況下,你可以通過在根元素中添加 v-once 指令來確保它只被評估一次,然後進行緩存,就像這樣。

Vue.component('terms-of-service', {
  template: `
    <div v-once>
      <h1>Terms of Service</h1>
      ... a lot of static content ...
    </div>
  `
})

3.遞歸組件

組件可以在自己的模板中遞歸調用自己,但是,它們只能通過 name 選項來調用。

如果你不小心,遞歸組件也可能導致無限循環:

name: 'stack-overflow',
template: '<div><stack-overflow></stack-overflow></div>'

像上面這樣的組件會導致“超過最大堆棧大小”的錯誤,所以要確保遞歸調用是有條件的即(使用 v-if 最終將為 false)

4.內聯模板

當特殊屬性 inline-template 存在於一個子組件上時,該組件將使用它的內部內容作為它的模板,而不是將其視為分佈式內容,這允許更靈活的模板編寫。

<my-component inline-template>
  <div>
    <p>These are compiled as the component's own template.</p>
    <p>Not parent's transclusion content.</p>
  </div>
</my-component>

5.動態指令參數

指令參數可以是動態的。例如,在 v-mydirective:[argument]=“value” 中, argument 可以根據組件實例中的數據屬性更新!這使得我們的自定義指令可以靈活地在整個應用程序中使用。

這是一條指令,其中可以根據組件實例更新動態參數:

<div id="dynamicexample">
  <h3>Scroll down inside this section ↓</h3>
  <p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p>
</div>
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    var s = (binding.arg == 'left' ? 'left' : 'top')
    el.style[s] = binding.value + 'px'
  }
})

new Vue({
  el: '#dynamicexample',
  data: function () {
    return {
      direction: 'left'
    }
  }
})

6.事件和鍵修飾符

對於 .passive、.capture 和 .once 事件修飾符,Vue提供了可與 on 一起使用的前綴:

例如:

on: {
  '!click': this.doThisInCapturingMode,
  '~keyup': this.doThisOnce,
  '~!mouseover': this.doThisOnceInCapturingMode
}

對於所有其他的事件和鍵修飾符,不需要專有的前綴,因為你可以在處理程序中使用事件方法。

7.依賴注入(Provide/Inject)

有幾種方法可以讓兩個組件在 Vue 中進行通信,它們各有優缺點。在2.2版本中引入的一種新方法是使用Provide/Inject的依賴注入。

這對選項一起使用,允許一個祖先組件作為其所有子孫的依賴注入器,無論組件層次結構有多深,只要它們在同一個父鏈上。如果你熟悉react,這與React的上下文功(context)能非常相似。

// parent component providing 'foo'
var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}

// child component injecting 'foo'
var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}

來自:https://blog.zhangbing.site/2021/04/09/7-vue-patterns-that-you-should-be-using-more-often/

翻譯自medium.com,作者:Fotis Adamakis

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10221

沐鳴娛樂_10種快速提高網站性能的方法

在這篇文章中,主要介紹10種快速提高網站性能的方法,你只需5分鐘內就可以將它應用到你的網站上,廢話不多說,讓我們進入正題吧 。

1. 文件壓縮

文件壓縮,可以減少網絡傳輸的字節數。有幾種壓縮算法。Gzip是最流行的,但是對於Brotli,你可以使用一種更新的、甚至更好的壓縮算法。如果想檢查您的服務器是否支持Brotli,可以使用 Brotli.pro。

如果你的服務器不支持Brotli,則可以按照以下簡單指南進行安裝 :

  • Nginx on Linux
  • Apache
  • NodeJs – Express

2. 圖像壓縮

未壓縮的圖像是一個巨大的潛在性能瓶頸。如果在將圖像提供給用戶之前沒有壓縮它們,那麼就會傳輸不必要的字節。有幾個有用的工具可以用於快速壓縮圖像且不損失可見質量。我主要使用Imagemin。它支持許多圖像格式,您w你以將其用作命令行界面或npm模塊。

imagemin img/* --out-dir=dist/images

你還可以 將npm 引入到項目里,使用imagemin-mozjpeg,可以將JPEG圖像壓縮到原有的60%:

const imagemin = require('imagemin');
const imageminMozjpeg = require('imagemin-mozjpeg');

(async() => {
  const files = await imagemin(
      ['img/*.jpg'],
      {
        destination: 'dist/img',
        plugins: [
          imageminMozjpeg({quality: 60}),
        ]
      }
  );
  console.log(files);
})();

就我而言,它將文件大小從4MB減小到100kB

3.圖像格式

使用現代圖像格式可以真正提高性能。 WebP 圖像比 JPEG 和 PNG 小,通常小25%-35%。 WebP 也被瀏覽器廣泛支持。

我們使用imagemin npm 包併為其添加WebP插件。 以下代碼將我的圖像的WebP版本輸出到dist文件夾中。

const imagemin = require('imagemin');
const imageminWebp = require('imagemin-webp');

(async() => {
  const files = await imagemin(
      ['img/*.jpg'],
      {
        destination: 'dist/img',
        plugins: [
          imageminWebp({quality: 50})
        ]
      }
  );
  console.log(files);
})();

結果表明,與原始圖像相比,文件大小減少了98%,與壓縮的 JPG 文件相比,WebP 對圖像的壓縮效果更加明顯,WebP版本比壓縮的JPEG版本小43%。

4.圖像延遲加載

延遲加載圖像是一種稍後而不是提前加載屏幕外圖像的技術。當解析器遇到正確加載的圖像時,會減慢初始頁面加載速度。通過延遲加載,可以加快這個過程並在以後加載圖像。使用lazysize很容易做到這一點。使用lazysize腳本和瀏覽器對loading屬性的支持,你可以這樣優化:

![](image.jpg)

改成:

![](image.jpg)

該庫會處理其餘的工作,你可以使用瀏覽器驗證這一點。打開你的網站,找到你的圖像標籤。如果類從lazyload更改為lazyloaded,它就可以工作。

5.緩存 http 頭

緩存是一種快速提高站點速度的方法。它減少了訪問者的頁面加載時間。我們可以告訴瀏覽器在特定的時間緩存文件,如果你對後台的知識有些了解,那麼配置緩存方不是很難的事情。

我們可以使用以下 API 進行緩存:

  • Cache-Control
  • ETag
  • Last-Modified

6. 內聯關鍵的 css

css 是阻塞渲染的,這意味着瀏覽器必須先下載並處理所有CSS文件,然後才能繪製像素。 通過內聯關鍵的 CSS,可以大大加快此過程。 我們可以通過以下步驟完成此操作:

識別關鍵的 CSS

如果你不知道你的關鍵CSS是什麼,你可以使用Critcal, CriticalCSS或Penthouse。所有這些庫都從給定視口可見的html文件中提取CSS。

criticalCSS 事例如下:

var criticalcss = require("criticalcss");

var request = require('request');
var path = require( 'path' );
var criticalcss = require("criticalcss");
var fs = require('fs');
var tmpDir = require('os').tmpdir();

var cssUrl = 'https://web.dev/app.css';
var cssPath = path.join( tmpDir, 'app.css' );
request(cssUrl).pipe(fs.createWriteStream(cssPath)).on('close', function() {
  criticalcss.getRules(cssPath, function(err, output) {
    if (err) {
      throw new Error(err);
    } else {
      criticalcss.findCritical("https://web.dev/", { rules: jsON.parse(output) }, function(err, output) {
        if (err) {
          throw new Error(err);
        } else {
          console.log(output);
          // save this to a file for step 2
        }
      });
    }
  });
});

內聯關鍵 CSS

html解析器遇到樣式標籤,並立即處理關鍵的CSS。

<head>
  <style>
  body {...}
  /* ... rest of the critical CSS */
  </style>
</head>

滯后非關鍵CSS

非關鍵的CSS不需要立即進行處理。 瀏覽器可以在onload事件之後加載它,因此用戶不必等待。

<link rel="preload" href="/assets/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/assets/styles.css"></noscript>

7. JavaScript 異步/延遲加載/延遲加載

HTML 也是阻塞渲染,瀏覽器必須等待 js 執行后才能完成對HTML的解析。但是我們可以告訴瀏覽器等待JavaScript執行。

異步加載JavaScript

使用屬性async,可以告訴瀏覽器異步加載腳本。

<script src="app.js" async></script>

延遲JavaScript

defer屬性告訴瀏覽器在 HTML 解析器解析完文檔之後運行腳本,但在事件發生之前,DOMContentLoaded會被觸發。

<script src="app.js" defer></script>

重複排序內聯的腳本

內聯腳本立即執行,瀏覽器對其進行解析。 因此,您可以將它們放在HTML的末尾,緊接在body標記之前。

8.使用資源提示優化性能

HTML5的資源提示(Resource Hints)可以簡單地理解為預加載,瀏覽器根據開發者提供的後續資源的提示進行有選擇性的加載和優化。“有選擇性”這一項是必須的且極其重要的,也是有別早先替代方案的重點,因為很多情況下,預加載會受到所分配到的計算資源以及帶寬資源的限制,瀏覽器有權放棄那些成本較高的加載項。

資源提示幫助開發人員告訴瀏覽器稍後可能加載的頁面。該規範定義了四種原語

  • preconnect
  • dns-prefetch
  • prefetch
  • prerender

此外,對於資源提示,我們使用了鏈接屬性的preload關鍵字。

preconnect

預鏈接, 使用方法如下:

<link rel="preconnect" href="https://example.com">

我們訪問一個站點時,簡單來說,都會經過以下的步驟:

  1. DNS 解析
  2. TCP 握手
  3. 如果為 Https 站點,會進行TLS握手

使用preconnect后,瀏覽器會針對特定的域名,提前初始化鏈接(執行上述三個步驟),節省了我們訪問第三方資源的耗時。需要注意的是,我們一定要確保preconnect的站點是網頁必需的,否則會浪費瀏覽器、網絡資源。

DNS Prefetch

DNS 預解析, 這個大多數人都知道,用法也很簡單:

<link rel="dns-prefetch" href="http://example.com">

DN S解析,簡單來說就是把域名轉化為ip地址。我們在網頁里使用域名請求其他資源的時候,都會先被轉化為ip地址,再發起鏈接。dns-prefeth使得轉化工作提前進行了,縮短了請求資源的耗時。

什麼時候使用呢?當我們頁面中使用了其他域名的資源時,比如我們的靜態資源都放在cdn上,那麼我們可以對cdn的域名進行預解析。瀏覽器的支持情況也不錯。

prefetch

預拉取, 使用方法如下:

<link rel="prefetch" href="index.html" as="document">
<link rel="prefetch" href="main.js" as="script">
<link rel="prefetch" href="main.css" as="style">
<link rel="prefetch" href="font.woff" as="font">
<link rel="prefetch" href="image.webp" as="image">

link標籤里的as參數可以有以下取值:

audio: 音頻文件
video: 視頻文件  
Track: 網絡視頻文本軌道 
script: javascript文件
style: css樣式文件
font: 字體文件   
image: 圖片   
fetch: XHR、Fetch請求
worker: Web workers
embed: 多媒體<embed>請求 
object:  多媒體<object>請求
document: 網頁

預拉取用於標識從當前網站跳轉到下一個網站可能需要的資源,以及本網站應該獲取的資源。這樣可以在將來瀏覽器請求資源時提供更快的響應。

如果正確使用了預拉取,那麼用戶在從當前頁面前往下一個頁面時,可以很快得到響應。但是如果錯誤地使用了預拉取,那麼瀏覽器就會下載額外不需要的資源,影響頁面性能,並且造成網絡資源浪費。

這裏需要注意的是,使用了prefetch,資源僅僅被提前下載,下載后不會有任何操作,比如解析資源。

prerender

預渲染,使用方法如下:

<link rel="prerender" href="//example.com/next-page.html">

prerender比prefetch更進一步。不僅僅會下載對應的資源,還會對資源進行解析。解析過程中,如果需要其他的資源,可能會直接下載這些資源。這樣,用戶在從當前頁面跳轉到目標頁面時,瀏覽器可以更快的響應。

preload

<link rel="preload" href="..." as="...">
<link rel="prefetch" href="...">

注意preload需要寫上正確的as屬性,才能正常工作喔(prefetch不需要)。但是它們有什麼區別呢?

  • preload 是用於預加載當前頁的資源,瀏覽器會優先加載它們
  • prefetch 是用於預加載後續導航使用的資源,瀏覽器也會加載它們,但優先級不高

9. 固定好你的谷歌字體

Google字體很棒,它們提供優質的服務,並被廣泛使用。 如果你不想自己託管字體,那麼Google字體是一個不錯的選擇。 你需要的是學習如何引用它們,哈里·羅伯茨(Harry Roberts)寫了一篇有關《The Fastest Google Fonts》的出色深度文章。 強烈建議你閱讀它。

如果你快速取用,那麼可以使用下面集成片段的谷歌字體:

<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=...&display=swap"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=...&display=swap" media="print" onload="this.media='all'"/>
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=...&display=swap"/></noscript>

10. 使用 service worker 緩存資源

service worker是瀏覽器在後台運行的腳本。緩存可能是最常用的特性,也是你應該使用的特性。我認為這不是一個選擇的問題。通過使用 service worker實現緩存,可以使 用戶 與站點的交互更快,並且即使用戶不在線也可以訪問站點。

總結

在這篇文章中,展示了 10 種快速的網絡性能,你可以在5分鐘內應用到你的網站,以提高你的網站速度。

感謝大家的觀看與支持,我們下期再見,不要忘了三連哦。

原文:https://dev.to/marcradziwill/

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10092

沐鳴平台網址_看看這13句 JavaScript單行代碼,會讓你看起來像個專家!

1. 獲取一個隨機布爾值 (true/false)

這個函數使用 Math.random() 方法返回一個布爾值(true 或 false)。Math.random 將在 0 和 1 之間創建一個隨機數,之後我們檢查它是否高於或低於 0.5。這意味着得到真或假的幾率是 50%/50%。

const randomBoolean = () => Math.random() >= 0.5;
console.log(randomBoolean());
// Result: a 50/50 change on returning true of false

2. 檢查日期是否為工作日

使用這個方法,你就可以檢查函數參數是工作日還是周末。

const isWeekday = (date) => date.getDay() % 6 !== 0;
console.log(isWeekday(new Date(2021, 0, 11)));
// Result: true (Monday)
console.log(isWeekday(new Date(2021, 0, 10)));
// Result: false (Sunday)

3. 反轉字符串

有幾種不同的方法來反轉一個字符串。以下代碼是最簡單的方式之一。

const reverse = str => str.split('').reverse().join('');
reverse('hello world');     
// Result: 'dlrow olleh'

4. 檢查當前 Tab 頁是否在前台

我們可以通過使用 document.hidden 屬性來檢查當前標籤頁是否在前台中。

const isBrowserTabInView = () => document.hidden;
isBrowserTabInView();
// Result: returns true or false depending on if tab is in view / focus

5. 檢查数字是否為奇數

最簡單的方式是通過使用模數運算符(%)來解決。如果你對它不太熟悉,這裡是 Stack Overflow 上的一個很好的圖解。

const isEven = num => num % 2 === 0;
console.log(isEven(2));
// Result: true
console.log(isEven(3));
// Result: false

6. 從日期中獲取時間

通過使用 toTimeString() 方法,在正確的位置對字符串進行切片,我們可以從提供的日期中獲取時間或者當前時間。

const timeFromDate = date => date.toTimeString().slice(0, 8);
console.log(timeFromDate(new Date(2021, 0, 10, 17, 30, 0))); 
// Result: "17:30:00"
console.log(timeFromDate(new Date()));
// Result: will log the current time

7. 保留小數點(非四舍五入)

使用 Math.pow() 方法,我們可以將一個数字截斷到某個小數點。

const toFixed = (n, fixed) => ~~(Math.pow(10, fixed) * n) / Math.pow(10, fixed);
// Examples
toFixed(25.198726354, 1);       // 25.1
toFixed(25.198726354, 2);       // 25.19
toFixed(25.198726354, 3);       // 25.198
toFixed(25.198726354, 4);       // 25.1987
toFixed(25.198726354, 5);       // 25.19872
toFixed(25.198726354, 6);       // 25.198726

8. 檢查元素當前是否為聚焦狀態

我們可以使用 document.activeElement 屬性檢查一個元素當前是否處於聚焦狀態。

const elementIsInFocus = (el) => (el === document.activeElement);
elementIsInFocus(anyElement)
// Result: will return true if in focus, false if not in focus

9. 檢查瀏覽器是否支持觸摸事件

const touchSupported = () => {
  ('ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch);
}
console.log(touchSupported());
// Result: will return true if touch events are supported, false if not

10. 檢查當前用戶是否為蘋果設備

我們可以使用 navigator.platform 來檢查當前用戶是否為蘋果設備。

const isAppleDevice = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
console.log(isAppleDevice);
// Result: will return true if user is on an Apple device

11. 滾動到頁面頂部

window.scrollTo() 方法會取一個 x 和 y 坐標來進行滾動。如果我們將這些坐標設置為零,就可以滾動到頁面的頂部。

注意:IE 不支持 scrollTo() 方法。

const goToTop = () => window.scrollTo(0, 0);
goToTop();
// Result: will scroll the browser to the top of the page

12. 獲取所有參數平均值

我們可以使用 reduce 方法來獲得函數參數的平均值

const average = (...args) => args.reduce((a, b) => a + b) / args.length;
average(1, 2, 3, 4);
// Result: 2.5

13. 轉換華氏度/攝氏度。(這個應該很少在國內用到吧)

處理溫度有時會讓人感到困惑。這 2 個功能將幫助你將華氏溫度轉換為攝氏溫度,反之亦然。

const celsiusToFahrenheit = (celsius) => celsius * 9/5 + 32;
const fahrenheitToCelsius = (fahrenheit) => (fahrenheit - 32) * 5/9;
// Examples
celsiusToFahrenheit(15);    // 59
celsiusToFahrenheit(0);     // 32
celsiusToFahrenheit(-20);   // -4
fahrenheitToCelsius(59);    // 15
fahrenheitToCelsius(32);    // 0

原文翻譯來自:https://medium.com/dailyjs/13-JavaScript-one-liners-thatll-make-you-look-like-a-pro-29a27b6f51cb

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10118

沐鳴開戶_ECMAScript 6 的Map映射

映射(Map)是 ECMAScript 6 規範中引入的一種數據結構。這是一種存儲鍵值對列表很方便的方法,類似於其他編程語言中的詞典或者哈希表。



什麼是映射

JavaScript 的對象(Object),本質上是鍵值對的集合(Hash結構),但是傳統上只能用字符串當作鍵,這給使用帶來了很大的限制。為了解決這個問題,ECMAScript 6 引入了 Map 數據結構。它類似於對象,也是鍵值對的集合,但是”鍵”的範圍不僅僅局限於字符串,而是各種類型的值(包括對象)都可以當作鍵。也就是說,Object 結構(對象結構)提供了”字符串—值”的對應,而 Map 結構提供了”值—值”的對應,是一種更完善的 Hash 結構的實現。

下面來看一個簡單的示例,了解Map的基本用法:

//聲明map實例
const page_info = new Map()
// 向 map 中添加元素
page_info.set("seo", {
"keywords": "infoq、Map",
"description":"Map對象是一種簡單的鍵/值映射,其中的鍵和值可以是任意值(原始值或對象的值)"
})
page_info.set("title", "JavaScript es6的map映射")
console.log(page_info)
console.log(typeof page_info) // object

輸出結果為:

Map {
'seo' => {
keywords: 'infoq、Map',
description: 'Map對象是一種簡單的鍵/值映射,其中的鍵和值可以是任意值(原始值或對象的值)'
},
'title' => 'javascript es6的map映射'
}
object

從輸出結果看,本質上Map(映射)就是一個 object 對象。



Object 與 Map 區別

Object 和 Map 的相似之處在於,都是按鍵存取一個值,而且鍵都是可以刪除的。可以看出,二者之間是非常相似的,它的不同這之處在於:

 MapObject意外的鍵 Map  默認情況不包含任何鍵。只包含顯式插入的鍵。

一個  Object  有一個原型, 原型鏈上的鍵名有可能和你自己在對象上的設置的鍵名產生衝突。

注意:  雖然 ES5 開始可以用  Object.create(null)  來創建一個沒有原型的對象,但是這種用法不太常見。

鍵的類型一個  Map 的鍵可以是 任意值 ,包括函數、對象或任意基本類型。一個 Object  的鍵必須是一個  String  或是 Symbol 。鍵的順序 Map  中的 key 是有序的。因此,當迭代的時候,一個  Map  對象以插入的順序返回鍵值。

一個  Object  的鍵是無序的

注意:自ECMAScript 2015規範以來,對象 確實 保留了字符串和 Symbol 鍵的創建順序; 因此,在只有字符串鍵的對象上進行迭代將按插入順序產生鍵。

size  Map  的鍵值對個數可以輕易地通過 size  屬性獲取 Object  的鍵值對個數只能手動計算迭代 Map  是 iterable 的,所以可以直接被迭代。迭代一個 Object 需要以某種方式獲取它的鍵然後才能迭代。性能在頻繁增刪鍵值對的場景下錶現更好。在頻繁添加和刪除鍵值對的場景下未作出優化。



Map映射常用方法

常用的 Map 方法有:賦值 set(key, value)  、獲取 get(key)  、移除指定鍵名及其對應的值delete(key) 、判斷是否存在 has(key)  、 獲取所有值 values()  、 key/value 迭代器 entries() 、遍歷 forEach() 和 清空所有鍵/值對 clear()   等。

聲明並初始化

const new_map = new Map();
console.log(new_map); //輸出:Map {}

賦值 set

賦值使用 map.set(key,value) ,可以用於增加新的 鍵/值 對或者修改 鍵/值 對,返回整個Map對象。

const page_info = new Map()
// 設置值
page_info.set("seo", {
"keywords": "infoq、Map",
"description":"Map對象是一種簡單的鍵/值映射,其中的鍵和值可以是任意值(原始值或對象的值)"
});
console.log(page_info);
page_info.set("seo", "seo信息");
console.log(page_info);

上面的示例增加值,並修改值。

Map {
'seo' => {
keywords: 'infoq、Map',
description: 'Map對象是一種簡單的鍵/值映射,其中的鍵和值可以是任意值(原始值或對象的值)'
}
}
Map { 'seo' => 'seo信息' }

獲取鍵值 get

使用  get(key)  獲取鍵值,如果獲取的  key->value  不存則返回  undefined

const page_info = new Map();
page_info.set("title", "javascript es6的map映射");
const title = page_info.get("title");
const seo_info = page_info.get("seo");
console.log(title); //javascript es6的map映射
console.log(seo_info); //undefined

刪除鍵值 delete

map.delete(key)  刪除指定  key  的鍵值對,返回成功或失敗結果,刪除成功返回 true ,刪除失敗返回 false 。

const page_info = new Map();
page_info.set("title", "javascript es6的map映射");
page_info.set("author", "infoq");
console.log(page_info); // Map { 'title' => 'javascript es6的map映射', 'author' => 'infoq' }

const deleted_author = page_info.delete("author");
const deleted_seo = page_info.delete("seo");
console.log(deleted_author); // true
console.log(deleted_seo); // false
console.log(page_info); // Map { 'title' => 'javascript es6的map映射' }

判斷鍵值是否存在 has

使用 map.has(key) 判斷指定 key 是否存在。

const page_info = new Map();
page_info.set("title", "javascript es6的map映射");
console.log(page_info); // Map { 'title' => 'javascript es6的map映射' }

console.log(page_info.has("title")); // true
console.log(page_info.has("seo")); // false

獲取所有鍵值 values()

const page_info = new Map();
page_info.set("title", "javascript es6的map映射");
page_info.set("author", "infoq");
console.log(page_info.values()); // [Map Iterator] { 'javascript es6的map映射', 'infoq' }

key/value 迭代器 entries()

使用 map.entries() 返回一個包含Map對象中每一個 [key, value] 數組的Iterator迭代器。

const page_info = new Map();
page_info.set("title", "javascript es6的map映射");
page_info.set("author", "infoq");
console.log(page_info.entries());

輸出的結果為:

[Map Entries] {
[ 'title', 'javascript es6的map映射' ],
[ 'author', 'infoq' ]
}

遍歷所有鍵值 forEach(callback)

const page_info = new Map();
page_info.set("title", "javascript es6的map映射");
page_info.set("author", "infoq");
page_info.forEach((value,key)=>{
console.log(key,value);
});

輸出的結果為:

title javascript es6的map映射
author infoq

清空Map映射所有鍵值 clear()

使用 map.clear() 清空Map所有的鍵值對。

const page_info = new Map();
page_info.set("title", "javascript es6的map映射");
page_info.set("author", "infoq");
page_info.clear();
console.log(page_info); // Map {}



與其它數據結構的轉換

Map映射轉為數組

Map轉為數組最方便方法是使用擴展運算符 …

const page_info = new Map();
page_info.set("title", "javascript es6的map映射");
page_info.set("author", "infoq");
console.log([...page_info]); // [ [ 'title', 'javascript es6的map映射' ], [ 'author', 'infoq' ] ]

Map映射轉為對象

function mapToObj(map) {
const obj = Object.create(null);
map.forEach((v,k)=>{
obj[k] = v;
});
return obj;
}
const page_info = new Map();
page_info.set("title", "javascript es6的map映射");
page_info.set("author", "infoq");

console.log( mapToObj(page_info));

輸出結果為:

[Object: null prototype] {
title: 'javascript es6的map映射',
author: 'infoq'
}

數組轉為Map映射

將數組傳入Map構造函數即可,即 new Map(array) 。

const page_info = [
["title","javascript es6的map映射"],
["author","infoq"]
];
console.log(new Map(page_info)); // Map { 'title' => 'javascript es6的map映射', 'author' => 'infoq' }

對象轉為Map

對象轉為Map映射通過 Object.entries() 。

const page_info = {
title:"javascript es6的map映射",
author:"infoq"
};
console.log(new Map(Object.entries(page_info))); // Map { 'title' => 'javascript es6的map映射', 'author' => 'infoq' }

映射Map轉為jsON

Map 轉為 jsON ,步驟是先把Map轉為對象,即前面的 mapToObj ,然後使用 JSON.stringify 方法

function mapToObj(map) {
const obj = Object.create(null);
map.forEach((v,k)=>{
obj[k] = v;
});
return obj;
}
function mapToJson(map){
return JSON.stringify(mapToObj(map));
}
const page_info = new Map();
page_info.set("title", "javascript es6的map映射");
page_info.set("author", "infoq");
console.log( mapToJson(page_info)); // {"title":"javascript es6的map映射","author":"infoq"}

原文 https://xie.infoq.cn/article/b12c6d6700992222617fb2e30


站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10102

沐鳴註冊平台官網_css3屬性: will-change

1. CPU和GPU

CPU即中央處理器,它的功能主要是解釋計算機指令以及處理計算機軟件中的數據,也被稱為主板。

GPU即圖形處理器,是與處理和繪製圖形相關的硬件。GPU是專為執行複雜的數學和幾何計算而設計的,有了它,CPU就從圖形處理的任務中解放出來,可以執行其他更多的系統任務

硬件加速(或者說GPU加速)是指在計算機中透過把計算量非常大的工作分配給專門的硬件來處理來減輕CPU的工作量的技術。在css transition, transform和animation的世界里,他暗示我們應該卸載進程到GPU,因此加快速度。這種情況通過向它自己的層疊加元素,當加載動畫的時候可以加速渲染。

硬件加速依賴於瀏覽器渲染頁面使用的layering model,當特定的操作(css 3D變形)作用於頁面上的一個元素,元素移動到它自己的layer,在這個layer中元素合一不受頁面其他元素的干擾獨立渲染,然後複合到頁面中去。在這種隔離內容渲染的工作方式下,如果頁面的變化僅僅是該元素的變形,其餘部分不必被重新渲染,這會帶來顯著的速度優勢。值得注意的是只有3D變形會有自己的layer,2D變形不會。

CSS的動畫、變形、漸變並不會自動的觸發GPU加速,而是使用瀏覽器稍慢的軟件渲染引擎。然而一些瀏覽器提供了hardware acceleration by means of certain properties來獲取更高的渲染性能。 舉個例子,opacity屬性是幾個能夠加速的屬性之一,因為GPU可以方便的處理。基本上任何層的透明度漸變瀏覽器都會交給GPU處理來加速。除了opacity能夠使用GPU處理的就是CSS 3D變形了

2. translateZ() (or translate3d()) Hack

我們都通過translateZ()或者translate3d() hack來騙取瀏覽器觸發硬件加速,具體做法就是為元素添加沒有變化的3D變形,比如元素在2維空間可以通過添加以下CSS來硬件加速

transform: translate3d(0, 0, 0);

然而強制使用hack方式創建layer並不是長久之計,創建layer的技術可以使頁面加速,但是也有代價,它們佔用RAM和GPU存儲空間(考慮到移動設備的存儲容量有限),所以必須小心使用,確保這麼做真的對頁面渲染有所幫助。為了避免創建layer的hacks,一個允許我們提前通知瀏覽器我們將對元素做何種變化的CSS屬性被引入,這樣瀏覽器可以優化處理元素渲染的方式,為元素提前準備昂貴的動畫處理操作,這就是wiil-change屬性。

3.wiil-change

will-change屬性可以提前通知瀏覽器我們要對元素做什麼動畫,這樣瀏覽器可以提前準備合適的優化設置。這樣可以避免對頁面響應速度有重要影響的昂貴成本。元素可以更快的被改變,渲染的也更快,這樣頁面可以快速更新,表現的更加流暢。

當對於素使用 CSS 3D變形時,元素及其內容可以在合成到頁面之前被創建到我們之前說的layer。然而把元素放到layer中是個昂貴的操作,這將會導致變形動畫延遲一個課件的瞬間,也就是flicker
為了避免這種延時,我們可以在發生之前通知瀏覽器,這樣瀏覽器會有一定的時間去準備這些變化,當發生的時候layer已經準備好了,這樣動畫酒會很流暢,不會閃屏。

will-change: transform;

可以寫多個屬性變化,逗號隔開

will-change: transform, opacity;

注意事項:

不要將 will-change 應用到太多元素上:瀏覽器已經儘力嘗試去優化一切可以優化的東西了。有一些更強力的優化,如果與 will-change 結合在一起的話,有可能會消耗很多機器資源,如果過度使用的話,可能導致頁面響應緩慢或者消耗非常多的資源。濫用會使頁面崩潰。。。

*,
*::before,
*::after {
    will-change: all;
}

雖然看起來很屌,但其實對頁面渲染傷害很大,這樣的規則設了和沒設沒什麼區別,瀏覽器本來就嘗試最優的渲染所有元素,就等於你讓老師重點照顧班裡每個同學一樣,就是廢話!

其實這甚至是有害的,因為一些操作會佔用太多的資源,甚至會導致頁面奔潰,就等於強制要求老師為每個學生補課,累死了。。。

有節制地使用:通常,當元素恢復到初始狀態時,瀏覽器會丟棄掉之前做的優化工作。但是如果直接在樣式表中顯式聲明了 will-change 屬性,則表示目標元素可能會經常變化,瀏覽器會將優化工作保存得比之前更久。所以最佳實踐是當元素變化之前和之後通過腳本來切換 will-change 的值。

不要過早應用 will-change 優化:如果你的頁面在性能方面沒什麼問題,則不要添加 will-change 屬性來榨取一丁點的速度。 will-change 的設計初衷是作為最後的優化手段,用來嘗試解決現有的性能問題。它不應該被用來預防性能問題。過度使用 will-change 會導致大量的內存佔用,並會導致更複雜的渲染過程,因為瀏覽器會試圖準備可能存在的變化過程。這會導致更嚴重的性能問題。

給它足夠的工作時間:這個屬性是用來讓頁面開發者告知瀏覽器哪些屬性可能會變化的。然後瀏覽器可以選擇在變化發生前提前去做一些優化工作。所以給瀏覽器一點時間去真正做這些優化工作是非常重要的。使用時需要嘗試去找到一些方法提前一定時間獲知元素可能發生的變化,然後為它加上 will-change 屬性。

在變化前立即為元素添加will-change幾乎沒有作用,可能還不如不設置,因為會導致新的layer創建,如下:

.element:hover {
    will-change: transform;
    transition: transform 2s;
    transform: rotate(30deg) scale(1.5);
}

需要給瀏覽器足夠的時間,如下:

.element {
    /* style rules */
    transition: transform 1s ease-out;
}
.element:hover {
    will-change: transform;
}
.element:active {
    transform: rotateY(180deg);
}

will-change顧名思義,通知瀏覽器即將發生的變化,而不是正在發生的變化。使用will-change,我們要求瀏覽器重點照顧我們聲明的元素,為了這個瀏覽器需要一定的時間來組織優化操作,這樣當變化發生的時候,優化才能沒有延遲的作用到元素

語法:

/* 關鍵字值 */
will-change: auto;
will-change: scroll-position;
will-change: contents;
will-change: transform;        /* <custom-ident>示例 */
will-change: opacity;          /* <custom-ident>示例 */
will-change: left, top;        /* 兩個<animateable-feature>示例 */
 
/* 全局值 */
will-change: inherit;
will-change: initial;
will-change: unset;
 
## auto ## 
表示沒有特別指定哪些屬性會變化,瀏覽器需要自己去猜,然後使用瀏覽器經常使用的一些常規方法優化。
## <animateable-feature> ##
 1) scroll-position 告訴瀏覽器,要不久后動畫啦(改變滾動條的位置或者使之產生動畫)
 2) contents:告訴瀏覽器 不久后改變元素內容中的某些東西,或者使它們產生動畫。
## <custom-ident> ## 
不久后改變指定的屬性名或者使之產生動畫。如果屬性名是簡寫,則代表所有與之對應的簡寫或者全寫的屬性。

瀏覽器兼容性:

Desktop

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
Basic support 36 36 (36)[1] 未實現 24 未實現

Mobile

Feature Android Firefox Mobile (Gecko) IE Phone Opera Mobile Safari Mobile
Basic support 37 36.0 (36) [1] 未實現 未實現 未實現

來自:https://www.cnblogs.com/hongplum/p/14622574.html

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10201

沐鳴註冊平台官網_ES6數組的擴展:Array.from()和Array.of()

一、 Array.from() : 將偽數組對象或可遍歷對象轉換為真數組

1.何為偽數組

如果一個對象的所有鍵名都是正整數或零,並且有length屬性,那麼這個對象就很像數組,語法上稱為“類似數組的對象”(array-like object),即為偽數組。

var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
obj[0] // 'a'
obj[1] // 'b'
obj.length // 3
obj.push('d') // TypeError: obj.push is not a function 

上面代碼中,對象obj就是一個類似數組的對象。但是“類似數組的對象”並不是數組,因為它們不具備數組特有的方法。對象obj沒有數組的push方法,使用該方法就會報錯。

2.有哪些是偽數組

典型的“類似數組的對象”是函數的arguments對象,以及大多數 DOM 元素集,還有字符串。

3.如何轉化為真數組

①數組的slice方法可以將“類似數組的對象”變成真正的數組

function doSomething(){
    console.log(arguments)
    var args = Array.prototype.slice.call(arguments);
    args.push("hj")
    console.log(args)
    return args
}
doSomething(1,2,3) 

或者你也可以寫成:

function doSomething(){
    var args = [].slice.call(arguments);
    return args
}
doSomething(1,2,3) 

儘管這種方法,也可以實現將類數組轉變為數組的目的,但並不直觀。ES6新增Array.from()方法來提供一種明確清晰的方式以解決這方面的需求,更推薦後者的辦法。

②Array.from()

<button>測試1</button>
<br>
<button>測試2</button>
<br>
<button>測試3</button>
<br>
<script type="text/JavaScript">
let btns = document.getElementsByTagName("button")
console.log("btns",btns);//得到一個偽數組
//btns.forEach(item=>console.log(item)) Uncaught TypeError: btns.forEach is not a function
Array.from(btns).forEach(item=>console.log(item))將偽數組轉換為數組
</script> 

在ES6中,擴展運算符(…)也可以將某些數據結構轉為數組。只不過它需要在背後調用遍歷器接口Symbol.iterator。值得注意的是如果一個對象沒有部署遍歷器接口,使用擴展運算符是無法將類似數組對象轉換成數組。

function doSomething (){ 
  return [...arguments] 
}
doSomething('a','b','c'); // ["a","b","c"] 

4.Array.from()用法

Array.from接受三個參數,但只有input是必須的:

  • input: 你想要轉換的類似數組對象和可遍歷對象
  • map: 類似於數組的map方法,用來對每個元素進行處理,將處理后的值放入返回的數組
  • context: 綁定map中用到的this

只要是部署了iterator接口的數據結構,Array.from都能將其轉為數組:

let arr = Array.from('juejin'); 
console.log(arr); //["j", "u", "e", "j", "i", "n"] 

Array.from還可以接受第二個參數,作用類似於數組的map方法,用來對每個元素進行處理,處理后的值放入返回的數組。

Array.from([1, 2, 3], (x) => x * x)// [1, 4, 9]
// 等同於
Array.from([1,2,3].map(x => x * x)) 

如果map函數裏面用到了this關鍵字,還可以傳入Array.from的第三個參數,用來綁定this。

Array.from()可以將各種值轉為真正的數組,並且還提供map功能。這實際上意味着,只要有一個原始的數據結構,你就可以先對它的值進行處理,然後轉成規範的數組結構,進而就可以使用數量眾多的數組方法。

Array.from({ length: 2 }, () => 'jack')// ['jack', 'jack'] 

二、Array.of(v1, v2, v3) : 將一系列值轉換成數組

當調用 new Array( )構造器時,根據傳入參數的類型與數量的不同,實際上會導致一些不同的結果, 例如:

let items = new Array(2) ;
console.log(items.length) ; // 2
console.log(items[0]) ; // undefined
console.log(items[1]) ; 
let items = new Array(1, 2) ;
console.log(items.length) ; // 2
console.log(items[0]) ; // 1
console.log(items[1]) ; // 2 

當使用單個數值參數來調用 Array 構造器時,數組的長度屬性會被設置為該參數。 如果使用多個參數(無論是否為數值類型)來調用,這些參數也會成為目標數組的項。數組的這種行為既混亂又有風險,因為有時可能不會留意所傳參數的類型。

ES6 引入了Array.of( )方法來解決這個問題。該方法的作用非常類似Array構造器,但在使用單個數值參數的時候並不會導致特殊結果。Array.of( )方法總會創建一個包含所有傳入參數的數組,而不管參數的數量與類型

let items = Array.of(1, 2);
console.log(items.length); // 2
console.log(items[0]); // 1
console.log(items[1]); // 2
items = Array.of(2);
console.log(items.length); // 1
console.log(items[0]); // 2 

Array.of基本上可以用來替代Array()或newArray(),並且不存在由於參數不同而導致的重載,而且他們的行為非常統一。

來自:https://www.cnblogs.com/xzsj/p/14628004.html

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10200

沐鳴:_React Server Component 可能並沒有那麼香

前段時間 React 團隊發布了一項用於解決 React 頁面在多接口請求下的性能問題的解決方案 React Server Components。當然該方案目前還在草案階段,官方也只是發了視頻和一個示例 demo 來說明這個草案。

Server Components

官方在視頻和 RFC 中說明了產生這個方案的主要原因是因為大量的 react 組件依賴數據請求才能做渲染。如果每個組件自己去請求數據的話會出現子組件要等父組件數據請求完成渲染子組件的時候才會開始去請求子組件的數據,也就是官方所謂的 WaterFall 數據請求隊列的問題。而將數據請求放在一起請求又非常不便於維護。

既然組件需要數據才能渲染,那為什麼接口不直接返回渲染后的組件呢?所以他們提出了 Server Components 的解決方案。我們暫且不管這其中的邏輯有沒有道理,先來看看該方案的大體流程是怎樣的。

方案的大概就是將 React 組件拆分成 Server 組件(.server.tsx)和 Client 組件(.client.tsx)兩種類型。其中 Server 組件會在服務端直接渲染並返回。與 SSR 的區別是 Server Components 返回的是序列化的組件數據,而不是最終的 html。

可能帶來的問題

通過接口將組件和組件的數據一併返回的方式帶來了打包體積的優勢,但是它真的能像 React Hooks 一樣香嗎?我覺得並不然。

接口返回

常規做法里前端 js 中加載組件,接口返回組件需要的數據。而 React Server Components 中則是將二者合二為一,雖然在打包體積上有所優化,但是明顯是把這體積轉義到了接口返回中。特別是在類似列表這種有分頁的請求中,這種劣勢會更明顯。明明組件只需要在初始的時候進行加載,但是因為被融合進接口裡了,每次接口都會返回冗餘的組件結構,這樣也不知道是好還是不好。可能後續需要優化一下接口二次返回只返回數據會比較好。

服務器成本問題

這裏所說的服務器成本有很多,首先是機器本身的成本。將客戶端渲染行為遷移到服務端時候勢必會增加服務端的壓力,用戶量上來之後這塊的成本是成量級的在增加的。關於這個問題,官方提供的回復是隨着服務器的成本降低勢必 Server Components 帶來的優勢會抵消這塊的劣勢。

Question: This might become more expensive for applications. In the search demo, finding those search results plus rendering them on the server is a more expensive operation than just an API call sent from the client.

Reply: We are moving some of the rendering to the server–so it’s true that your server will be doing more work than before. But server costs are constantly going down, and far more powerful than most consumer devices. I think React Server Components will give you the ability to make that tradeoff and choose where you best want the work to be done, on a per component basis. And that’s not something that’s easily possible today.
via: 《RFC: React Server Components》

不過以目前我所在的業務情況來看,服務器的成本還是非常貴的,為了降低成本大家紛紛將邏輯下發到邊緣計算甚至是客戶端處理。一方面是為了節省成本,另一方面也是為了降低壓力加快處理。

除了機器本身的成本之外,請求的成本也會增加。畢竟除了數據請求之外還要處理組件渲染,而且這塊作為組件耦合不好進行拆分。相比較常規方案,使用 js 文件加載組件到客戶端,接口單純返回數據,這塊的時間成本增加了非常多。特別是常規方案中 JS 文件加載完之後是在瀏覽器中緩存的,後續的成本非常小。

體積問題可能還好,但是請求時間增加了這個可能就非常致命了。

心智負擔

這點在 RFC 中也有說明。由於 Server Components 中無法使用 useState, useReduce, useEffect, DOM API 等方法,勢必這會給使用者帶來大量的心智負擔。雖然官方說會使用工具讓開發者做到無感,且會提供運行時報錯,但是我相信光是想什麼時候需要寫 Server Componet 什麼時候需要寫 Client Component 就已經腦殼疼了吧,更別提還有個 Shared Component 了。

另外還有就是增加了跨端的流程之後,調試的成本也會變的非常高。別說很多人沒有服務端的經驗,就算是有相關經驗的同學可能也沒辦法很好的在服務端進行快速定位。關於這個問題官方提供的說法是可以依賴內部的錯誤監控和日誌服務。

回歸問題的本質

讓我們回歸到問題的本質,React Server Component 的目的其實是為了解決接口請求分散在各組件中帶來的子組件的數據請求需要等待父組件請求完成渲染子組件時才能開始請求的數據請求隊列問題。那麼除了 Server Component 之外沒有其它的解決方案了嗎?其實不然。

const [childData, setData] = useState([]); useEffect(() => { fetchChildData.then(setData); }, []); if(!data.length) { return null; } return ( {data.length + childData.length} ); } ReactDOM.render(, document.querySelector(‘#root’));” title=”” data-original-title=”複製”>

import React, {useState, useEffect} from 'react';
import ReactDOM from 'react-dom';

function App() {
  const [data, setData] = useState([]);
  useEffect(() => {
    fetchData.then(setData);
  }, []);
  
  return (
    <div> {!data.length ? 'loading' : null} <Child data={data} /> </div>
  );
}

function Child({data}) {
  const [childData, setData] = useState([]);
  useEffect(() => {
    fetchChildData.then(setData);
  }, []);
  
  if(!data.length) {
    return null;
  }
  
  return (
    <div>{data.length + childData.length}</div>
  );
}

ReactDOM.render(<App />, document.querySelector('#root'));

如示例代碼所示,只要加載組件,但是在無數據情況下不返回 DOM 也是可以做到子組件的數據先請求而無需等待的。當然這種需要認為的在寫法上進行優化,但我也仍然認為比大費周章的去做 Server Component 要好很多。

至於 Server Component 帶來的打包體積優化這個問題,我覺得 RFC 裏面的評論說的非常的好。”比起 83KB(gzip 后大概是 20KB)打包體積,我覺得在項目中為了格式化日期使用一個 83KB 的庫這才是更大的問題。“

Removing a 83KB (20KB gzip) library isn’t a big deal, I would say the bigger problem here is that you’re using a 83KB library to format dates.

via: 《RFC: React Server Component》

實際上官方列舉的兩點關於日期處理以及 Markdown 格式處理的庫,可以看到都是針對於數據進行處理的需求。針對這種情況如果覺得這塊的體積非常”貴“的話完全是可以讓服務端將格式化后的數據返回,這樣豈不是更小成本的解決了這個問題?

後記

看完 《RFC: React Server Component》 中所有的討論,大部分人對 Server Component 還是持不贊成的態度的,認為它可能並沒有像 React Hooks 那樣解決業務中的實際痛點。就目前暴露的提案,我個人也覺得 Server Component 是弊大於利的。目前就期望官方如果要實現的話能解耦實現,不要影響未使用 Server Component 的 React 用戶打包體積。

當然該提案我覺得不是沒有好處,它最大的好處我個人認為是帶來了 React 組件序列化的官方標準。為多端、多機、多語言之間實現 React 組件交流提供了基礎。基於這套序列化方案,我們可以實現組件緩存存儲,多機器併發渲染組件等。至於多語言實現也是在 RFC 討論中大家比較關心的問題,通過這套序列化標準讓其它語言去實現 React 組件也不是沒有可能。

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10114