1. 程式人生 > >ES6-Promise

ES6-Promise

type 返回 ace 傳遞 tor 改變 don 統一 tar

依賴文件地址 :https://github.com/chanceLe/ES6-Basic-Syntax/tree/master/js

  1 <!DOCTYPE html>
  2 <html>
  3     <head>
  4         <meta charset="UTF-8">
  5         <title>[es6]-15-promise</title>
  6         <script src="./js/browser.js"></script>
  7         <script 
type="text/babel"> 8 /* 9 * Promise是異步編程的一種解決方案,比傳統的回調函數和事件更合理,更強大。 10 * 由社區最早提出和實現,ES6寫入了標準,統一了用法,原生提供了Promise對象。 11 * 12 * 所謂Promise,就是一個容器,裏面保存著某個未來才會結束的事件(通常是異步操作)的結果。 13 * 從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。promise提供統一的API,各種異步操作
14 * 都可以用同樣的方法進行處理。 15 * 16 * Promise對象有以下兩個特點: 17 * 1.對象的狀態不受外界影響。promise對象代表一個異步操作,有三種狀態,pending,Resolved(Fullfilled)和 18 * Reject。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這種狀態。 19 * 2.一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從pending
20 * 變成Resolved 或 從pending 變成 Rejected。只要這兩種情況發生,狀態就凝固了,就算再發生了變化,然後添加的 21 * 回調函數,也會得到promise狀態改變時的結果。 這與event完全不同,event的特點是錯過了,再監聽是得不倒結果的。 22 * 23 * 有了Promise對象,可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。提供統一的接口,使得控制 24 * 異步操作更加容易。 25 * 26 * Promise也有一些缺點: 27 * 1.一旦新建,就會立即執行,無法中途取消 28 * 2.如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部 29 * 3.當處於pending狀態時,無法得知目前進展到哪一個階段。 30 * 31 * 如果某些事件不斷地反復發生,一般來說,使用stream模式比部署Promise更好。 32 * 33 *基本用法: 34 * es6規定,promise是一個構造函數,用來生成promise實例。 35 * 36 * var promise = new Promise(function(resolve,reject){ 37 * //some code 38 * if( 異步操作成功){ 39 * resolve(value) 40 * }else{ 41 * reject(error) 42 * } 43 * }) 44 * 45 * promise構造函數接受一個函數作為參數,這個函數的兩個參數分別是resolve和reject,這是兩個函數,由js引擎提供,不用自己部署。 46 * 47 * promise的實例生成以後,可以用then方法分別指定Resolved狀態和Reject狀態的回調函數。 48 * promise.then(function(value){ 49 * //success 50 * },function(error){ 51 * //failure 52 * }) 53 * 54 * then方法可以接受兩個回調函數作為參數。第一個回調函數是Promise對象的狀態變為Resolved時調用,第二個是狀態變為Reject時調用。 55 * 第二個函數是可選的,不一定要提供。這兩個函數都接受Promise對象傳出的值作為參數。 56 */ 57 function timeout(ms){ 58 return new Promise((resolve,reject)=>{ 59 setTimeout(resolve,ms,done); 60 }) 61 } 62 timeout(100).then((value)=>{ 63 console.log(value); 64 }) 65 66 //Promise新建後會立即執行 67 let promise = new Promise(function(resolve,reject){ 68 console.log(Promise); 69 resolve(); 70 }) 71 promise.then(function(){ 72 console.log("Resolved") 73 }) 74 console.log("hi!") 75 76 //Promise.prototype.then() 77 /* 78 * promise實例具有then方法,也就是說這個方法定義在原型上。then方法返回的是一個 79 * 新的promise實例(註意 不是原來那個Promise實例),可以采用鏈式寫法,then方法後面再 80 * 調用一個then方法。 81 * 82 * 采用鏈式的then,可以指定一組按照次序調用的回調函數。這時,前一個回調函數, 83 * 有可能返回的還是一個promise對象,這時後一個回調函數,就會等待該Promise對象的狀態發生變化,才會被調用。 84 */ 85 86 //Promise.prototype.catch() 87 /* 88 * Promise.prototype.catch()是.then(null,rejection)的別名,用於指定發生錯誤時的回調函數。 89 * 下面有一個例子: 90 */ 91 var promise1 = new Promise(function(resolve,reject){ 92 throw new Error("test"); 93 }) 94 promise1.catch((err)=>{console.log(err)}); 95 96 //如果Promise的狀態已經變成Resolved,再拋出錯誤是是無效的。 97 var promise2 = new Promise(function(resolve,reject){ 98 resolve("OK"); 99 throw new Error("test2"); 100 }) 101 promise2.catch((err)=>{console.log(err)}); //沒有執行,已經變成Reslved狀態。 102 103 //Promise對象的錯誤具有冒泡的性質,會一直向後傳遞,直到被捕獲為止,也就是說,錯誤總是會被下一個catch語句捕獲。 104 //一般來說,不要在then方法裏面定義reject狀態的回調函數,總是使用catch方法。 105 //catch方法返回的也是一個Promise對象,因此可以配合then方法進行鏈式調用。 106 107 //promise.all方法用於將多個promise實例包裝成一個新的Promise實例。 108 /* 109 * var p = Promise.all([p1,p2,p3]) 110 * 接受一個數組作為參數,數組成員都是Promise實例,如果不是就通過Promise.resolve方法,將參數轉為 111 * Promise實例,再進一步處理。 .all()方法的參數可以不是數組,但必須具有Iterator接口。 112 * 113 * p的狀態由p1,p2,p3決定,分兩種情況: 114 * 1.只有p1,p2,p3的狀態都變成fullfilled,p的狀態才會變成fullfilled,此時p1,p2,p3的返回值組成一個數組,傳給p的回調函數。 115 * 2.只要p1,p2,p3中有一個beireject,p的狀態就變成reject,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。 116 */ 117 118 /* 119 * Promise.race() 120 * 同樣將多個Promise實例,包裝成一個新的Promise實例。 121 * var p = Promise.race([p1,p2,p3]); 122 * 只要有一個實例率先改變狀態,p的狀態就會跟著改變。那個率先改變的Promise實例的返回值,就傳遞給p的回調函數。 123 * 如果參數不是Promise對象,會通過Promise.resolve方法,轉為Promise對象。 124 */ 125 126 /* 127 * Promise.resolve() 128 * 將現有對象轉為Promise對象,Promise.resolve方法就起到這個作用。 129 * 130 * Promise.resolve("foo") 等價於 131 * new Promise(resolve => resolve("foo")) 132 * 133 * Promise.resolve參數分為四種情況: 134 * 1.參數是一個promise實例: 原封不動的返回這個實例. 135 * 2.參數是一個thenable對象,指的是具有then方法的對象. 136 * 比如 : 137 * let thenable = { 138 * then(resolve,reject){ 139 * resolve(45); 140 * } 141 * } 142 * promise.resolve方法會將這個對象轉為Promise對象,然後立即執行thenable對象的then方法。 143 * 3.如果參數是一個原始值,或者是一個不具有then方法的對象,則Promise.resolve方法返回一個新的 144 * Promise對象,狀態為Resolved。 145 */ 146 var p = Promise.resolve("hello"); 147 p.then(function(s){ 148 console.log(s); 149 }) //hello 150 151 /* 152 * 4.不帶有任何參數 153 * 直接返回一個Resolved狀態的Promise對象。 154 * 如果希望得倒一個Promise對象,比較方便的方法就是直接調用Promise.resolve()方法。 155 * 需要註意,立即resolve的Promise對象,是本輪事件循環的結束時,而不是在下一輪事件循環的開始時。 156 */ 157 158 /* 159 * Promise.reject() 160 * 返回一個新的Promise實例,狀態為rejected.參數用法與Promise.resolve方法完全一致。 161 */ 162 var p2 = Promise.reject("出錯了!"); //等同於 163 var p3 = new Promise((resolve,reject)=>reject("出錯了!")); 164 p2.then(null,(s)=>{console.log(s)}); 165 166 // 兩個有用的附加方法 167 /* 168 * 1.done 169 * Promise對象的回調鏈,不管以then方法或catch方法結尾,要是最後一個方法拋出錯誤,都有可能無法捕捉到( 170 * 因為Promise內部的錯誤不會冒泡到全局)。因此,我們可以提供一個done方法,總是處於回調鏈的尾端,保證拋出任何可能出現的錯誤。 171 * done可以提供fullfilled和reject狀態的回調函數,也可以不提供任何參數,done都會捕捉到任何可能出現的錯誤,並向全局拋出。 172 */ 173 174 /* 175 * 2.finally 176 * 用於指定不管Promise對象最後狀態如何,都會執行的操作。它與done的最大區別,它接受一個普通的回調函數作為參數,該函數不管怎樣都必須執行。 177 */ 178 179 /* 180 * 應用 181 * 1.圖片加載 182 * 可以將圖片的加載,寫成一個Promise,一旦加載完成,Promise 的狀態就發生變化。 183 */ 184 const preloadImg = function(path){ 185 return new Promise(function(resolve,reject){ 186 var image = new Image(); 187 image.onload = resolve; 188 image.onerror = reject; 189 image.src=path; 190 }) 191 } 192 193 //2.Generator函數與Promise的結合 194 //使用Generator函數管理流程,遇到異步操作的時候,通常返回一個Promise對象。 195 function getFoo(){ 196 return new Promise(function(resolve,reject){ 197 resolve("foo"); 198 }) 199 } 200 var g = function*(){ 201 try{ 202 var foo = yield getFoo(); 203 console.log(foo); 204 }catch(e){ 205 console.log(e); 206 } 207 } 208 209 function run(generator){ 210 var it = generator(); 211 function go(result){ 212 if(result.done) return result.value; 213 214 return result.value.then(function(value){ 215 return go(it.next(value)); 216 },function(error){ 217 return go(it.throw(error)); 218 }) 219 } 220 go(it.next()); 221 } 222 run(g); 223 224 //上面代碼的Generator函數g之中,有一個異步操作getFoo,它返回的就是一個promise對象。 225 //函數run用來處理這個promise對象,並調用下一個next方法。 226 </script> 227 </head> 228 <body> 229 </body> 230 </html>

ES6-Promise