一、microtasks、macrotasksjavascript
JavaScript是單線程執行的,而如今推行的多線程執行,均可以理解爲僞多線程,由於全部的執行都會迴歸的主線程執行,html
而主線程外會有如多個事件隊列,等待主線程的空閒後進入執行。vue
而microtasks與macrotasks就是很好理解事件環的概念,而後它在不一樣的瀏覽器的執行順序可能不一致,但不妨去理解它。java
V8實現中,兩個隊列各包含不一樣的任務:node
macrotasks(宏任務): script(總體代碼),setTimeout, setInterval, setImmediate, I/O, UI rendering
瀏覽器
microtasks(微任務): process.nextTick, Promises, Object.observe, MutationObserver
多線程
以上爲事件環的執行圖解,microtasks與macrotasks的執行過程。app
在如今瀏覽器中可能使用到就script(總體代碼),setTimeout,setInterval,UI rendering,Promises等,而其餘可能不經常使用,若是是nodeJs可能就經常使用。
框架
資料一異步
從資料中能夠知道microtasks這個是會阻塞瀏覽器渲染的,由於它是在主線程一空閒下來就執行,而macrotasks就是在瀏覽器渲染後再執行,能夠利用
這一特性有效的提升性能,如vue裏的nextTick就是觸發microtasks,那麼就能夠實現多線程執行且瀏覽器渲染阻塞等待處理後執行來提升性能,而不是
每次的更新都要執行渲染,那樣會很消耗性能,但microtasks的執行會比事件冒泡都要優先,因此這裏就會出現事件觸發後當前事件執行了,後就執行
microtasks裏的,而後再執行冒泡,因此還要把事件強制爲macrotasks,而vue就是這樣的處理邏輯。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> #a{ width: 200px; height: 200px; background: #000; } #b{ width: 100px; height: 100px; background: #ff7600; } </style> </head> <body> <div id="a"> <div id="b"></div> </div> <script> var a = document.querySelector("#a"); var b = document.querySelector("#b"); a.onclick = function(){ console.log("a"); } b.onclick = function(){ pp(); console.log("b"); } function pp(){ setTimeout(function(){ console.log("timeout"); },0); new Promise(function(resolve){ console.log("Promise"); resolve(); }).then(function(){ console.log("then"); }); } </script> </body> </html> 結果: Promise b then a timeout
從上例子可知,microtasks真的厲害。。。。也證明的以上概念。
javascript是一門單線程語言,無論是什麼新框架新語法糖實現的所謂異步,其實都是用同步的方法去模擬的,緊緊把握住單線程這點很是重要。
事件循環是js實現異步的一種方法,也是js的執行機制。
二、函數柯里化
把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數並且返回結果的新函數的技術。
這增長了函數的適用性,但同時也下降了函數的適用範圍。
函數柯里化工具方法實現:
一:
function curry(){ var args = [].slice.call(arguments); var fnLen = 0; var fn = args[0]; if(typeof fn !== 'function'){ console.error('first param is not function!'); return null; } fnLen = fn.length; args.shift(); if(args[0] instanceof Array){ args = args[0]; } return function(){ var _args = [].slice.call(arguments); [].push.apply(args,_args); if(args.length >= fnLen){ return fn.apply(this, args); } return arguments.callee } } // 例子一 function fb(a,b,c,d,e,f,g){ console.log([].slice.call(arguments)); } fb = curry(fb,[10,20,30,40]); console.log(fb(50)(60)(70)); fb = curry(fb); console.log(fb(10)(20)(30)(40)(50)(60)(70)); // 例子二 function fss(v,b,n,m,x){ console.log([].slice.call(arguments)); } fss = curry(fss,107,270,307,407); console.log(fss(50));
此方法爲只有被柯里化的函數的參數所有傳遞後才能執行函數,而參數傳遞完後還調用就會報錯。
二:
function curry(){ var args = [].slice.call(arguments); var fn = args[0]; if(typeof fn !== 'function'){ console.error('first param is not function!'); return null; } args.shift(); if(args[0] instanceof Array){ args = args[0]; } return function(){ var _args = [].slice.call(arguments); [].push.apply(args,_args); arguments.callee.valueOf = function(){ return fn.apply(this, args); } return arguments.callee; } } function fss(v,b,n,m,x){ console.log([].slice.call(arguments)); } fss = curry(fss,107,270,307,407); console.log(fss(50)(30)(100)(1000));
這種柯里化使用的隱形轉換toString,valueOf等實現,由於轉換在函數調用的最後一步執行,此能夠實現無限傳參,無參數長度的限制。
柯里化是爲了讓函數的自由度增大,但也犧牲了一些性能,但在一些封裝裏會讓代碼更加順暢,且優雅,由於一些重複代碼能夠省略。