##小程序改基,大世界
###簡(jiǎn)介
· 小程序解決了什么問題
· 小程序技術(shù)棧
HTML/CSS/JavaScript ? NodeJS
移動(dòng)適配
HTTP協(xié)議/HTTPS
OAuth2
GIT
· 主流的小程序平臺(tái)
·類似?小程序的技術(shù)
Cordova:通過webview渲染怠缸,通過插件調(diào)?用系統(tǒng)服務(wù)
PWA:Service Worker和Push API
React Native/Weex:JavaScript通過JavaScriptCore等執(zhí)?行行樟蠕,并
通過Bridges和Native組件交互
Flutter:Dart直接與獨(dú)?立系統(tǒng)的UI庫(kù)進(jìn)?行行交互
###小程序的技術(shù)架構(gòu)
? ?文件結(jié)構(gòu)及其含義
.json 后綴的 JSON 配置?文件
.wxml 后綴的 WXML 模板?文件
.wxss 后綴的 WXSS 樣式?文件
.js 后綴的 JS 腳本邏輯?文件
?文件結(jié)構(gòu)及其含義:JSON
?文件結(jié)構(gòu)及其含義:WXML
本質(zhì)是HTML模版
有特定的標(biāo)簽
接管?一些簡(jiǎn)單的邏輯判斷
JS不不直接操作DOM貌亭,只負(fù)責(zé)set數(shù)據(jù)
?文件結(jié)構(gòu)及其含義: WXSS
提供rpx單位
精簡(jiǎn)的CSS
提供全局和局部的CSS
?文件結(jié)構(gòu)及其含義: JS
負(fù)責(zé)邏輯交互
APP 柬唯、Page、Component三個(gè)構(gòu)造函數(shù)
可調(diào)?用系統(tǒng)API
? 雙線程模型
? 生命周期
? 組件
? 其他
插件機(jī)制
云端函數(shù)
?小游戲
###開發(fā)發(fā)布流程
開發(fā)者在?小程序平臺(tái)注冊(cè)?小程序圃庭,以獲得APPID
初始化代碼并完成代碼倉(cāng)庫(kù)配置
開發(fā)代碼并調(diào)試
上傳并發(fā)布
###小程序的發(fā)展
多端同構(gòu)框架
?自動(dòng)化
硬件框架
云IDE
W3C?小程序?工作組
同構(gòu)框架
意義:?一次編寫適配多端,?一次迭代各端同步
利利?用Web的優(yōu)點(diǎn),以及對(duì)各個(gè)平臺(tái)進(jìn)?行行動(dòng)態(tài)適配
?小程序?自動(dòng)化
控制?小程序跳轉(zhuǎn)到指定?頁(yè)?面 ? 獲取?小程序?頁(yè)?面數(shù)據(jù)
獲取?小程序?頁(yè)?面元素狀態(tài)
觸發(fā)?小程序元素綁定事件
往 AppService 注?入代碼?片段 ? 調(diào)?用 wx 對(duì)象上任意接?口
硬件框架
云IDE
W3C小程序工作組
##Web前端點(diǎn)播直播入門
###什么是視頻丈屹?
1先蒋、格式與內(nèi)容
· 文件擴(kuò)展名≈媒體封裝格式(媒體容器類型)
· 媒體封裝格式≠音視頻編碼格式(使用了誰家的編碼器)
· 文件內(nèi)容:
1) 頭信息(格式业岁、時(shí)長(zhǎng)允耿、幀率念链、碼率君编、分辨率...)
2) 索引信息
3) 視頻數(shù)據(jù)
4) 音頻數(shù)據(jù)
5) 附加增強(qiáng)數(shù)據(jù)...
2兑燥、視頻數(shù)據(jù)
· 顯示器顏色呈現(xiàn)基于RGB(紅綠藍(lán))顏色空間模型
· 視頻領(lǐng)域大多基于YUV顏色空間做抽樣存儲(chǔ)
· 幀內(nèi)預(yù)測(cè)&幀間預(yù)測(cè)復(fù)用進(jìn)一步有效的壓縮數(shù)據(jù)
· P幀(前向預(yù)測(cè)幀)除师、B幀(雙向預(yù)測(cè)幀)搓侄、I幀(參考幀)
· 基于通用標(biāo)準(zhǔn)集N多技術(shù)于一身 --- 視頻編碼器
H.264(AVC)、H.265(HEVC)泊交、VP8乳讥、VP9...
3、音頻數(shù)據(jù)
· 聲音:不同振幅&頻率而產(chǎn)生的機(jī)械波廓俭;數(shù)字形式是一維波形
· 對(duì)自然中連續(xù)的聲波采樣云石,做數(shù)字化PCM存儲(chǔ)
· 揚(yáng)聲器還原PCM(脈沖編碼調(diào)制)數(shù)字信號(hào)為模擬音頻信號(hào)
· 音頻壓縮基本算法:預(yù)測(cè)、變換
· 基于通用標(biāo)準(zhǔn)集N多技術(shù)于一身 --- 音頻編碼器???????
AAC研乒、MP3...
4汹忠、傳輸協(xié)議
傳統(tǒng)場(chǎng)景
流媒體(直播)
· HLS:蘋果為利用現(xiàn)有CDN設(shè)施而發(fā)明的"流媒體"協(xié)議
· HTTP(S)-FLV:基于HTTP的流媒體協(xié)議
· RTMP、RTP/RTSP、TS宽菜、MMS...
點(diǎn)播傳輸
· HTTP(S):通過Range方式或參數(shù)方式完成Seek
Web端
·HTTP(S)谣膳、WS(S)、P2P...
5铅乡、播放器原理
· 解協(xié)議(加載數(shù)據(jù))
· 解封裝(解復(fù)用)
· 解碼
· 渲染
###好玩的WebAPI
1继谚、媒體兼容判斷
let videoEl = document.createElement("video");
let types = {
? 'mp4': 'audio/mp4',
? 'MP4': 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
? 'webm': 'video/webm; codecs="vp8, vorbis"',
? 'ogg': 'video/ogg; codecs="theora, vorbis"',
? 'm3u8': 'application/vnd.apple.mpegURL',
? 'ts': 'video/mp2t; codecs="avc1.42E01E,mp4a.40.2"'
};
Object.keys(types).forEach(key => {
? const type = types[key];
? const ret = videoEl.canPlayType(type) || '不支持';
? console.log(key + ': ' + ret);
});
2、交互式視頻
let video = $('video');
video.ontimeupdate = ()=>{
? let {currentTime} = video;
? show(currentTime > 64 ? '.s2' : '.s1');
? hide(currentTime > 64 ? '.s1' : '.s2');
? if(
? ? (currentTime > 64 && currentTime < 65) ||
? ? (currentTime > 113 && currentTime < 114)
? ){
? ? video.pause();
? }
};
let ppBtn = $('paly_pause');
video.onplay = ()=>{
? ppBtn.innerText = '暫停';
};
video.onpause = ()=>{
? ppBtn.innerText = '播放';
};
ppBtn.onclick = ()=>{
? video[video.paused ? 'play' : 'pause' ]();
};
$('start').onclick = ()=>{
? video.currentTime = 1;
? video.play();
};
$('step').onclick = ()=>{
? video.currentTime = 60;
? video.play();
};
$('dream').onclick = ()=>{
? video.currentTime = 83;
? video.play();
};
$('drink').onclick = ()=>{
? video.currentTime = 116;
? video.play();
};
hide('.s2');
function show(sel){
? document.querySelectorAll(sel).forEach(el=>{
? ? el.style.display='inline'
? });
}
function hide(sel){
? document.querySelectorAll(sel).forEach(el=>{
? ? el.style.display='none'
? });
}
function $(id){
? return document.getElementById(id);
}
3阵幸、播放本地視頻文件
let iptFileEl = document.querySelector('input[type="file"]');
let videoEl = document.querySelector('video');
iptFileEl.onchange = e =>{
? let file = iptFileEl.files && iptFileEl.files[0];
? playFile(file);
};
function playFile(file){
? if(file){
? ? let fileReader = new FileReader();
? ? fileReader.onload = evt => {
? ? ? if(FileReader.DONE == fileReader.readyState){
? ? ? ? videoEl.src = fileReader.result;
? ? ? }else{
? ? ? ? console.log('FileReader Error:', evt);
? ? ? }
? ? }
? ? fileReader.readAsDataURL(file);
? }else{
? ? videoEl.src = '';
? }
}
4花履、播放硬件資源(調(diào)用攝像頭或麥克風(fēng))
const getUserMediaPromise = options => new Promise((resolve, reject) => {
? const nvgt = window.navigator;
? if(nvgt) {
? ? if(nvgt.mediaDevices && nvgt.mediaDevices.getUserMedia) {
? ? ? return nvgt.mediaDevices.getUserMedia(options).then(resolve, reject);
? ? }
? ? const getUserMedia = nvgt.getUserMedia || nvgt.webkitGetUserMedia || nvgt.mozGetUserMedia;
? ? if(getUserMedia) {
? ? ? return getUserMedia(options, resolve, reject)
? ? }
? }
? reject('當(dāng)前環(huán)境不支持獲取媒體設(shè)備。');
});
let streamTrack;
const video = document.querySelector('video');
document.querySelector('#play').onclick = () => {
? getUserMediaPromise({
? ? audio: false,
? ? video: true
? }).then(stream => {
? ? video.srcObject = stream;
? ? streamTrack = stream.getTracks()[0];
? },
? err => {
? ? console.log('getUserMedia error: [' + err.name + '] ' + err.message)
? });
};
document.querySelector('#stop').onclick = () => {
? streamTrack && streamTrack.stop();
};
const box = document.querySelector('div');
document.querySelector('#sketch').onclick = () => {
? box.className = box.className ==='' ? 'sketch' : '';
};
5挚赊、實(shí)現(xiàn)視頻錄制
const getUserMediaPromise = options => new Promise((resolve, reject) => {
? const nvgt = window.navigator;
? if(nvgt) {
? ? if(nvgt.mediaDevices && nvgt.mediaDevices.getUserMedia) {
? ? ? return nvgt.mediaDevices.getUserMedia(options).then(resolve, reject);
? ? }
? ? const getUserMedia = nvgt.getUserMedia || nvgt.webkitGetUserMedia || nvgt.mozGetUserMedia;
? ? if(getUserMedia) {
? ? ? return getUserMedia(options, resolve, reject)
? ? }
? }
? reject('當(dāng)前環(huán)境不支持獲取媒體設(shè)備诡壁。');
});
const video = document.querySelector('#preview');
let cameraStream;
const opencameraBtn = document.querySelector('#opencamera');
const closecameraBtn = document.querySelector('#closecamera');
const recordBtn = document.querySelector('#record');
const stopRecordBtn = document.querySelector('#stoprecord');
const playBtn = document.querySelector('#play');
const downloadBtn = document.querySelector('#download');
opencameraBtn.onclick = () => getUserMediaPromise({
? audio: false,
? video: true
}).then(
? stream => {
? ? cameraStream = video.srcObject = stream;
? ? opencameraBtn.disabled = true;
? ? closecameraBtn.disabled = false;
? ? recordBtn.disabled = false;
? },
? err => {
? ? console.log('getUserMedia error: [' + err.name + '] ' + err.message)
? }
);
closecameraBtn.onclick = () => {
? cameraStream && cameraStream.getTracks()[0].stop();
? cameraStream = null;
? opencameraBtn.disabled = false;
? closecameraBtn.disabled = true;
? stopRecordBtn.onclick();
};
let mediaRecorder;
let recordedBlobs;
const mimeType = ['video/webm;codecs=vp9', 'video/webm;codecs=vp8', 'video/webm', ''].find(type => {
? return MediaRecorder.isTypeSupported(type);
});
// console.log('mimeType', mimeType);
recordBtn.onclick = () => {
? recordedBlobs = [];
? try {
? ? mediaRecorder = new MediaRecorder(cameraStream, { mimeType });
? } catch(e) {
? ? alert('Exception while creating MediaRecorder: ' + e + '. mimeType: ' + mimeType);
? ? return;
? }
? recordBtn.disabled = true;
? stopRecordBtn.disabled = false;
? playBtn.disabled = true;
? downloadBtn.disabled = true;
? mediaRecorder.onstop = evt => {
? ? console.log('Recorder stopped');
? };
? mediaRecorder.ondataavailable = function(event) {
? ? if (event.data && event.data.size > 0) {
? ? ? recordedBlobs.push(event.data);
? ? }
? };
? mediaRecorder.start(20); // 單次收集數(shù)據(jù)毫秒時(shí)長(zhǎng),ondataavailable 觸發(fā)頻率時(shí)長(zhǎng)間隔
};
const recordedVideo = document.querySelector('#recorded');
stopRecordBtn.onclick = () => {
? mediaRecorder && mediaRecorder.stop();
? mediaRecorder = null;
? // console.log('Recorded Blobs: ', recordedBlobs);
? recordedVideo.controls = true;
? playBtn.disabled = false;
? downloadBtn.disabled = false;
? stopRecordBtn.disabled = true;
? if(!cameraStream) {
? ? recordBtn.disabled = true;
? }
};
const getRecordedBlobUrl = () => {
? const superBuffer = new Blob(recordedBlobs, {type: mimeType.split(';')[0]});
? return window.URL.createObjectURL(superBuffer);
};
playBtn.onclick = () => {
? recordedVideo.src = getRecordedBlobUrl();
}
downloadBtn.onclick = () => {
? var a = document.createElement('a');
? a.style.display = 'none';
? a.href = getRecordedBlobUrl();
? a.download = 'test.webm';
? document.body.appendChild(a);
? a.click();
? setTimeout(function() {
? ? document.body.removeChild(a);
? ? window.URL.revokeObjectURL(url);
? }, 100);
}
6咬腕、播放JS拉取的媒體數(shù)據(jù)
const video = document.querySelector('video');
const fetchMp4 = (url, cb) => {
? const xhr = new XMLHttpRequest();
? xhr.open('get', url);
? xhr.responseType = 'arraybuffer';
? xhr.onload = function () {
? ? cb(xhr.response);
? };
? xhr.send();
};
const assetURL = 'https://nickdesaulniers.github.io/netfix/demo/frag_bunny.mp4';
const mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
// 創(chuàng)建動(dòng)態(tài)媒體源欢峰,并關(guān)聯(lián)到video元素上
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', () => {
? const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
? // 拉取數(shù)據(jù)
? fetchMp4(assetURL, buf => {
? ? sourceBuffer.addEventListener('updateend', () => {
? ? ? // 媒體流傳輸完畢
? ? ? mediaSource.endOfStream();
? ? ? // video.play();
? ? });
? ? // 將數(shù)據(jù)喂給 Video -- 注意這里只是一次性輸入整個(gè)MP4數(shù)據(jù)
? ? sourceBuffer.appendBuffer(buf);
? });
});
###Web端點(diǎn)播直播&播放器解決方案
1、點(diǎn)播直播的區(qū)別
應(yīng)用流程
· 點(diǎn)播:創(chuàng)作者 => 上傳 => 轉(zhuǎn)碼 => 存儲(chǔ) <=> CDN分發(fā) <=> 觀眾
· 直播:創(chuàng)作者 => 推流 <=> 存儲(chǔ) <=> 轉(zhuǎn)碼 <=> CDN分發(fā) <=> 觀眾
媒體類型的選擇
· HTTP(S)-MP4.. 點(diǎn)播服務(wù)
· HTTP(S)-FLV 點(diǎn)播涨共、直播
· HTTP(S)-HLS 點(diǎn)播纽帖、直播(高延遲)
2、播放器解決方案
原生瀏覽器支持的
· 直接走原生Video播放
原生瀏覽器不支持的
· 協(xié)議或容器類型不支持
JS解協(xié)議下載數(shù)據(jù)举反、解容器懊直、重新封裝,然后通過MSE喂給Video解碼火鼻、渲染播放
例如Web端播放FLV室囊、HLS:http://chimee.org
· 解碼器不支持
JS下載數(shù)據(jù),WASM 解容器魁索、解碼融撞,通過 WebGL&WebAudio 渲染播放
例如Web端播放HEVC編碼視頻:https://zyun.#/developer/doc?did=QHWWPlayer
· 有解密需求的
參考前兩條,在解容器之后對(duì)每幀數(shù)據(jù)啟用解密邏輯粗蔚。
##前端代碼的自我修養(yǎng)
如何衡量代碼質(zhì)量的好壞尝偎?
衡量代碼質(zhì)量的唯一有效標(biāo)準(zhǔn):WTF/min —— Robert C. Martin
代碼的自我修養(yǎng)
· 代碼規(guī)范
· 格式
· 流程化
代碼規(guī)范:
安裝Eslint:yarn global add eslint
使用Eslint規(guī)范代碼
流程化:
如何優(yōu)雅地提交代碼
· git commit message規(guī)范
· 合并提交
##技術(shù)翻譯:進(jìn)階的直梯
1、翻譯類型
文學(xué)翻譯 非文學(xué)翻譯
藝術(shù)成分多一些 科學(xué)成分多一些
需要更多的靈感 需要更多的勤奮
責(zé)任小一些 責(zé)任大一些
2鹏控、技術(shù)翻譯的意義
翻譯技術(shù)文章致扯,學(xué)習(xí)新技術(shù)思想
翻譯技術(shù)文檔,掌握標(biāo)準(zhǔn)和工具
翻譯技術(shù)圖書当辐,獲得名聲和報(bào)酬
3抖僵、技術(shù)翻譯的標(biāo)準(zhǔn)
準(zhǔn)確、地道缘揪、簡(jiǎn)潔
4耍群、技術(shù)翻譯的方法
消化吸收原文
母語地道表達(dá)
就是翻譯意思
5义桂、技術(shù)翻譯要堅(jiān)持技術(shù)驅(qū)動(dòng)
示例原文
An object literal can only use a symbol as a property inside the computed property syntax.
let s1 = Symbol('foo'),
let o = {
? [s1]: 'foo val'
};
// Also valid:
// o[s1] = 'foo val';
console.log(o);
// {Symbol{foo}: foo val}
參考譯文
對(duì)象字面量只能在計(jì)算屬性語法中使用符號(hào)作為屬性。
語法中使用符號(hào)作為屬性世吨。