ES6-Promise
Posted 橙云生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES6-Promise相关的知识,希望对你有一定的参考价值。
依赖文件地址 :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的主要内容,如果未能解决你的问题,请参考以下文章