天天看點

05慕課網《進擊Node.js基礎(一)》HTTP概念進階(同步/異步)

HTTP子產品介紹

支援http協定的更多特性

不緩存請求和響應

API比較底層處理流相關,資訊解析

HTTP相關概念

回調

将函數作為參數傳到執行函數中,參數函數在執行函數中嵌套執行

function learn(something){
    console.log(something);
}

function we(callback,something){
    something+=' is cool'
    callback(something)
}
//具名函數
we(learn,'Nodejs')
//匿名函數
we(function(something){
    console.log(something)
},'hello')      

同步/異步

JavaScript中的異步函數

//在指定間隔内執行一次
setTimeout(function(){
   alert('1')
},2000)      
//在執行間隔内重複執行,但是需要關閉alert,不會彈出N個
setInterval(function(){
   alert('1')
},2000)      

同步

任務順序執行,等待上一個執行完成再執行下一個

//同步
var c=0
function print(){
    console.log(c)
}

function plus(){
    setTimeout(function(){
        console.log('aaa')
    },1000)
    c+=1;
}
plus()
print()      
05慕課網《進擊Node.js基礎(一)》HTTP概念進階(同步/異步)

異步

setTimeout()不隻是是一個異步函數,它還涉及到了計時器線程

多個setTimeout()函數首先按照先後順序壓入異步函數隊列中

主程式執行完畢後開始執行異步函數隊列

異步隊列中若是setTimeout函數,則放到計時器線程中

在計時器線程中,如果時間相等,則按進入線程的先後順序執行

若有A,B線程,A正在執行,但是B已經到了該執行的時間,那麼B不會執行,直到等待A執行完畢才會執行

若異步隊列中有需要立即執行的函數,那麼久首先執行,A會等待,一次隻執行一個

或者是setTimeout()函數首先放到計時器線程當中,等到指定的時間放入執行隊列當中

每個任務都有多個回調函數,前一個任務執行完畢後不執行下一個任務,而是執行回調函數;後一個任務按照任務的排列順序執行,不會等待上一個任務執行完畢

//異步,任務執行完成後執行回調函數
var c=0
function print(){
    console.log(c)
}

function plus(callback){
    setTimeout(function(){
        c+=1;
        callback()
    },1000)
    console.log('a')
}
plus(print)      
05慕課網《進擊Node.js基礎(一)》HTTP概念進階(同步/異步)

有關異步的一個問題:https://www.jianshu.com/p/e5225ba4a025

參考閉包:http://www.jb51.net/article/24101.htm

//以下代碼的輸出是什麼?如何修改
for (var i = 1; i <= 5; i++) {
    setTimeout( function(){  //function timer()可以是具名函數
        console.log(i);
    },i*1000);
}
//輸出5個6:6 6 6 6 6 6
//因為setTimeou函數是異步的,在正文執行完後,i=6的時候開始執行,而且是執行5次,是以列印5個6      

錯誤答案:

for (var i = 1; i <= 5; i++) {
    setTimeout( function(i){  //function timer()可以是具名函數
        console.log(i);
    },i*1000);
}

//輸出5 個 undefined;調用匿名函數,沒有傳值,i引用的是參數i的值,i為undefined      

正确答案一:

for (var i = 1; i <= 5; i++) {
    (function() {
        var j = i;
        setTimeout( function() {
            console.log(j);
        },i*1000 ); //這一行将i*1000改為j*1000也行,并不影響
    })();
}
//此處用了立即執行函數(function(){})();使setTimeout中函數形成了閉包
//什麼是閉包:當内部函數(setTimeout中的匿名函數) 在定義它的作用域(立即執行函數) 的外部(立即執行函數外部) 被引用時(異步,最後調用,在外部調用)
//      就建立了該内部函數(匿名函數)的閉包 
//      如果内部函數(匿名函數)引用了位于外部函數的變量,當外部函數調用完畢後,這些變量在記憶體不會被 釋放,因為閉包需要它們.

//根據閉包的定義,我們面對這個問題的思路:
// 匿名函數function(){ console.log(j) }外要再套一層立即執行函數
// j為引用立即執行函數中的變量
// 通過異步調用匿名函數      

正确答案二:使用let塊級作用域形成閉包,不太了解就不說了

for (var i = 1; i <= 5; i++) {
    let j = i;
    setTimeout(function timer() {
        console.log(j);
    },j*1000);
}      
歸納一下就是:函數裡面有函數,函數外面調用裡面函數;但是函數外面怎麼調用函數裡面的函數呢?
1.使用異步,異步是最後執行;上面的例子是這樣
2.該函數的結果為裡面的函數,先var fn=該函數,然後執行fn,這樣就形成了閉包      

I/O

磁盤上資料讀寫

單線程/多線程

一次隻能進行一個請求和響應

多個請求和響應同時進行

阻塞/非阻塞

阻塞:用戶端一直等待服務端響應

非阻塞:請求無響應就去幹别的,過段時間再請求

事件

點選,移動等操作

事件驅動

函數在事件發生的時候執行

基于事件驅動的回調

函數中的回調函數

事件循環

密集任務異步執行放到loop隊列,單線程不斷查詢loop隊列