摘要:源碼結(jié)構(gòu)簡要解析文件結(jié)構(gòu)圖片腳本音頻入口文件直接依賴查看代碼可以直接發(fā)現(xiàn)依賴樣式腳本依賴分析腳本首先第一段代碼定義了三個主要的全局方法定義模塊,由存儲,模塊本質(zhì)是函數(shù),這里參照模塊規(guī)范。
Fruit-Ninja 源碼結(jié)構(gòu)簡要解析
文件結(jié)構(gòu)images 圖片
scripts 腳本
sound 音頻
index.html 入口 html 文件
直接依賴查看 index.html 代碼可以直接發(fā)現(xiàn)依賴:
樣式images/index.css
腳本scripts/all.js
依賴分析 腳本void function(global){ var mapping = {}, cache = {}; global.startModule = function(m){ require(m).start(); }; global.define = function(id, func){ mapping[id] = func; }; global.require = function(id){ if(!/.js$/.test(id)) id += ".js"; if(cache[id]) return cache[id]; else return cache[id] = mapping[id]({}); }; }(this);all.js
首先第一段代碼定義了三個主要的全局方法
define: 定義模塊,由mapping存儲,模塊本質(zhì)是函數(shù),這里參照 AMD 模塊規(guī)范。
require: 加載指定模塊,模塊名后綴.js 處理、cache緩存模塊。
startModule: 加載并啟動模塊,通過 start()函數(shù)可以確定模塊內(nèi)部必須實現(xiàn) start 函數(shù)用以初始化模塊。
剩下的全是 define 函數(shù),把所有腳本注冊到 mapping 里面,最后加載 main 模塊 并啟動。
main模塊all.js內(nèi)scripts/main.js模塊
var timeline = require( "timeline" ); var tools = require( "tools" ); var sence = require( "sence" ); var Ucren = require( "lib/ucren" ); var buzz = require( "lib/buzz" ); var control = require( "control" ); var csl = require( "object/console" ); var message = require( "message" ); var state = require( "state" );
先加載依賴,這里 require 是首次開始運行,它首先會補全該模塊路徑后綴,然后嘗試讀取 cache 緩存,如果之前有加載過就不會重復(fù)加載,如果是第一次加載則會從 mapping 模塊中心找到指定 id 的模塊函數(shù)并直接執(zhí)行出結(jié)果,并在返回該結(jié)果前將之緩存。
我們接著看第一個依賴timeline到底返回的是什么結(jié)果,找到它的 define 函數(shù)
define("scripts/timeline.js", function(exports){ /** * a easy timeline manager * @version 0.9 * @author dron */ var Ucren = require("scripts/lib/ucren"); /** * initialize timeline */ exports.init = function(){ var me = this; me.startTime = now(); me.count = 0; // var interval = function(){ // me.count ++; // update( now() ); // requestAnimationFrame( interval ); // }; // interval(); var time = 1; // if( Ucren.isSafari ) // time = 10; setInterval( function(){ me.count ++; update( now() ); }, time ); }; /** * create a task * @param {Object} conf the config * @return {Task} a task instance */ exports.createTask = function( conf ){ /* e.g. createTask({ start: 500, duration: 2000, data: [a, b, c,..], object: module, onTimeUpdate: fn(time, a, b, c,..), onTimeStart: fn(a, b, c,..), onTimeEnd: fn(a, b, c,..), recycle: [] }); */ var task = createTask(conf); addingTasks.unshift( task ); adding = 1; if( conf.recycle ) this.taskList( conf.recycle, task ); return task; }; /** * use a array to recycle the task * @param {Array} queue be use for recycling task * @param {Task} task a task instance * @return {Array} this queue */ exports.taskList = function( queue, task ){ if( !queue.clear ) queue.clear = function(){ for(var task, i = this.length - 1; i >= 0; i --) task = this[i], task.stop(), this.splice( i, 1 ); return this; }; if( task ) queue.unshift( task ); return queue; }; /** * create a timer for once callback * @param {Function} fn callback function * @param {Number} time time, unit: ms */ exports.setTimeout = function( fn, time ){ // e.g. setTimeout(fn, time); return this.createTask({ start: time, duration: 0, onTimeStart: fn }); }; /** * create a timer for ongoing callback * @param {Function} fn callback function * @param {Number} time time, unit: ms */ exports.setInterval = function( fn, time ){ // e.g. setInterval(fn, time); var timer = setInterval( fn, time ); return { stop: function(){ clearInterval( timer ); } }; }; /** * get the current fps * @return {Number} fps number */ exports.getFPS = function(){ var t = now(), fps = this.count / (t - this.startTime) * 1e3; if(this.count > 1e3) this.count = 0, this.startTime = t; return fps; }; /** * @private */ var Ucren = require("scripts/lib/ucren"); var tasks = [], addingTasks = [], adding = 0; var now = function(){ return new Date().getTime(); }; var createTask = function( conf ){ var object = conf.object || {}; conf.start = conf.start || 0; return { start: conf.start + now(), duration: conf.duration == -1 ? 86400000 : conf.duration, data: conf.data ? [0].concat( conf.data ) : [0], started: 0, object: object, onTimeStart: conf.onTimeStart || object.onTimeStart || Ucren.nul, onTimeUpdate: conf.onTimeUpdate || object.onTimeUpdate || Ucren.nul, onTimeEnd: conf.onTimeEnd || object.onTimeEnd || Ucren.nul, stop: function(){ this.stopped = 1; } } }; var updateTask = function( task, time ){ var data = task.data; data[0] = time; task.onTimeUpdate.apply( task.object, data ); }; var checkStartTask = function( task ){ if( !task.started ){ task.started = 1; task.onTimeStart.apply( task.object, task.data.slice(1) ); updateTask( task, 0 ); } }; var update = function(time){ var i = tasks.length, t, task, start, duration, data; // TODO: 三八五時檢查一下 tasks 有沒有釋放完成 // document.title = i; while( i -- ){ task = tasks[i]; start = task.start; duration = task.duration; if( time >= start ){ if( task.stopped ){ tasks.splice( i, 1 ); continue; } checkStartTask( task ); if( ( t = time - start ) < duration ) updateTask( task, t ); else updateTask( task, duration ), task.onTimeEnd.apply( task.object, task.data.slice(1) ), tasks.splice( i, 1 ); } } if( adding ){ tasks.unshift.apply( tasks, addingTasks ); addingTasks.length = adding = 0; } };; return exports; });
timeline 字面意思時間軸,先是引入了lib/ucren依賴,發(fā)現(xiàn)這個依賴是爛代碼沒有用,接著為形參 exports(傳入的實際參數(shù)是一個空對象)定義了一系列方法,包括:
init: 初始化時間軸
createTask: 創(chuàng)建任務(wù)
...
具體邏輯不作贅述,最后將 exports 作為結(jié)果返回了,于是 timeline 就有了 setTimeout 這個屬性,
var setTimeout = timeline.setTimeout.bind( timeline );
bind 是繼承自 Function 基類的一個屬性,用于改變當(dāng)前函數(shù)內(nèi)部 this 指向,可以確定timeline.setTimeout內(nèi)有使用 this,
exports.setTimeout = function( fn, time ){ // e.g. setTimeout(fn, time); return this.createTask({ start: time, duration: 0, onTimeStart: fn }); };
果不其然,this.createTask同樣是 timeline 才有的屬性,才要綁定 timeline,不然運行時無法判斷 this 指向的對象是否有這么一個屬性去調(diào)用。
start 啟動函數(shù)里面使用 invoke 分別調(diào)用了timeline, sence, control的 init 方法
Array.prototype.invoke = function( method ){ var args = slice.call( arguments, 1 ); this.forEach(function( item ){ if(item instanceof Array) item[0][method].apply( item[0], item.slice(1) ); else item[method].apply( item, args ); }); return this; };
打印日志,3 秒后執(zhí)行 sence.switchSence.saturate,saturate同樣是由Ucren庫提供的Function靜態(tài)方法,作用是返回一個函數(shù),這個函數(shù)是原函數(shù)對象 this 忽略自己接受的參數(shù),僅接受指定參數(shù)的版本,目前來看除了動了參數(shù)列表意外看不懂到底是干嘛的
Function.prototype.saturate = function(scope){ var fn = this, afters = slice.call( arguments, 1 ); return function(){ return fn.apply( scope, slice.call( arguments, 0 ).concat( afters ) ); } };
接下來監(jiān)聽了兩個自定義事件,slice和slice.at
最后對運行環(huán)境進(jìn)行判斷并給出相關(guān)提示
相關(guān)鏈接https://ucren.com/blog/archiv...
https://github.com/ChineseDro...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/98631.html
摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理從模板到的簡要流程今天的計劃是, 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基...
摘要:當(dāng)發(fā)現(xiàn)該路徑為文件夾時則,則依次查找如下文件字段擴(kuò)展名文件解析文件可以定位之后,則是解析定位下來的文件了,本文用的是,文檔如規(guī)范文檔解析文件返回一個語法樹。對語法樹進(jìn)行遍歷對遇到為且其為為的節(jié)點將該節(jié)點的以及下標(biāo)包裝成對象儲存起來。 前言 自動化打包工具webpack,相信很多人和我一樣嘗試著研究下它,但是繁雜的功能以及高度抽象的代碼實在是很難理解,所以筆者只能通過github的web...
摘要:本文將從源碼從此深入分析配置文件的解析,配置存儲,與配置查找。在學(xué)習(xí)配置文件的解析過程之前,需要先了解一下模塊與指令的一些基本知識。 運營研發(fā)團(tuán)隊 李樂 配置文件是nginx的基礎(chǔ),對于學(xué)習(xí)nginx源碼甚至開發(fā)nginx模塊的同學(xué)來說更是必須深究。本文將從源碼從此深入分析nginx配置文件的解析,配置存儲,與配置查找。 看本文之前讀者可以先思考兩個問題: 1.nginx源碼中隨處可以...
摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理源碼版之掛載組件由這篇文章從模 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于...
閱讀 3072·2021-10-11 10:58
閱讀 1989·2021-09-24 09:47
閱讀 503·2019-08-30 14:19
閱讀 1684·2019-08-30 13:58
閱讀 1444·2019-08-29 15:26
閱讀 641·2019-08-26 13:45
閱讀 2139·2019-08-26 11:53
閱讀 1772·2019-08-26 11:30