瞭解JavaScript中的Promise

2020-10-07 11:00:36

學習記錄,加深印象

1. 回撥函數

JavaScript是單執行緒,因此JavaScript中的瀏覽器事件、網路操作需要非同步執行,而非同步執行可以用回撥函數實現

	function callback() {
	    console.log('Done');
	}
	console.log('before setTimeout()');
	setTimeout(callback, 1000); // 1秒鐘後呼叫callback函數
	console.log('after setTimeout()');
  • callback回撥函數,作為JundgeNum的引數
	function JundgeNum(num,callback){
	   if(num<0)
	       return setTimeout(callback,1000,1)
	   setTimeout(callback,1000,null,num)   //null,num表示callback的一二引數
	}
	JundgeNum(2,function(err,succ){
	   if(err)
	       console.log('數位小於0')
	   else                     //當callback中err引數為null時
	       console.log('成功,數位為'+succ)
	})
	console.log('test')
	//test
	//成功,數位為2    (1秒後出現)
  • 將callback的兩個引數(err,succ)拆開為兩個函數來看,分別作為JundgeNum的兩個引數
    function JundgeNum(num,succ,err)
    {
      if(num<0)
          return setTimeout(err, 1000)
      setTimeout(succ, 1000)
    }
    JundgeNum(1,function(){
        console.log('成功,數位大於0')        
    },function(){
        console.log('err數位小於0')
    })
   	console.log('test')
	//test
   	//成功,數位大於0

2.回撥地獄

回撥套回撥,當回撥巢狀很深時,就稱為回撥地獄

    function JundgeNum(num,succ,err){
        if(num<0)
            return setTimeout(err, 1000,num)
        setTimeout(succ, 1000,num)
    }
    JundgeNum(2,function(num){
        console.log(num) 
        JundgeNum(4,function(num){
            console.log(num)
            JundgeNum(3,function(num){
                console.log(num)
                JundgeNum(5,function(num){
                	console.log(num)             
            	})                
            })             
        })
    })
	//4
	//16
	//9
	//25

3.Promise

  • Promise是一個建構函式,因此我們可以new Promise得到一個Promise的範例物件
  • 在Promise上,有兩個函數,resolve(成功之後的回撥函數),reject(失敗之後的回撥函數)
  • 在Promise建構函式的Prototype屬性上,有一個.then()方法,也就是說,只要是Promise建構函式建立的範例,都可以存取到.then()方法
  • 我們可以在new出來的Promise範例上,呼叫.then()方法,預先為這個非同步操作,指定成功 (resolve)和失敗(reject)回撥函數
    function JundgeNum(num){
        return promise=new Promise(function(resolve,reject){
            if(num<0) return setTimeout(reject,1000)
            setTimeout(resolve,1000,num*num)
        })
    }
    JundgeNum(-1).then(function(num){
        console.log(num)       //預先指定成功resolve函數
    },function(){
        console.log('小於0')        //預先指定失敗reject函數
    })
    //小於0
  • 在上一個.then中,返回一個新的promise範例,可以繼續用下一個.then處理
    function JundgeNum(num){
        return promise=new Promise(function(resolve,reject){
            setTimeout(resolve,1000,num)
        })
    }
    var p=JundgeNum(2)
    p.then(function(num){
        console.log(num)
        return JundgeNum(num*num)
    }).then(function(num){
        console.log(num)
        return JundgeNum(num*num)
    }).then(function(num){
        console.log(num)
    })
    //2
    //4
    //16

Promise單純的為了解決回撥地獄的問題,並不能幫我們減少程式碼量

廖雪峰官方網站例子

// 0.5秒後返回input*input的計算結果:
function multiply(input) {
    return new Promise(function (resolve, reject) {
        console.log('calculating ' + input + ' x ' + input + '...');
        setTimeout(resolve, 500, input * input);
    });
}

// 0.5秒後返回input+input的計算結果:
function add(input) {
    return new Promise(function (resolve, reject) {
        console.log('calculating ' + input + ' + ' + input + '...');
        setTimeout(resolve, 500, input + input);
    });
}

var p = new Promise(function (resolve, reject) {
    console.log('start new Promise...');
    resolve(2);
});

p.then(multiply)
 .then(add)
 .then(multiply)
 .then(add)
 .then(function (result) {
    console.log('Got value: ' + result);
});

Promie中捕獲異常的兩種方式

  1. 如果前面的Promise執行失敗,但不想讓後續的Promise操作被終止,可以為每個Promise指定失敗的回撥
    function JundgeNum(num){
        return promise=new Promise(function(resolve,reject){
            if(num>0||num===0)
                return setTimeout(resolve,1000,num)
            setTimeout(reject,1000,num)
        })
    }
    var p=JundgeNum(0)
    p.then(function(num){
        console.log(num)
        return JundgeNum(num-1)
    },function(err){
        console.log(err+'!!數值為負')
        return JundgeNum(err-1)
    })
    .then(function(num){
        console.log(num)
        return JundgeNum(num-1)
    },function(err){
        console.log(err+'!!數值為負')
        return JundgeNum(err-1)
    })
    .then(function(num){
        console.log(num)
    },function(err){
        console.log(err+'!!數值為負')
    })
    //0
    //-1!!數值為負
    //-2!!數值為負
  1. 如果後續的promise執行依賴於前面promsie執行的結果,因此前面失敗了後面沒有執行下去的意義,則立即終止所有的Promise執行,這時可用.catch()
    function JundgeNum(num){
        return promise=new Promise(function(resolve,reject){
            if(num>0||num===0)
                return setTimeout(resolve,1000,num)
            setTimeout(reject,1000,num)
        })
    }
    var p=JundgeNum(0)
    p.then(function(num){
        console.log(num)
        return JundgeNum(num-1)
    }).then(function(num){
        console.log(num)
        return JundgeNum(num-1)
    }).then(function(num){
        console.log(num)
    }).catch(function(err){
        console.log(err+'!!數值為負')
    })
    //0
    //-1!!數值為負
catch的作用:如果前面有任何的Promise執行失敗,則立即終止所有Promise的執行,並馬上進入catch去處理Promise中丟擲的異常