Promise对象——ECMAScript 6 入门笔记(一)
来源:互联网 发布:折扇起源知乎 编辑:程序博客网 时间:2024/05/18 03:17
14.1含义
Promise保存着一个异步操作的结果
特点
- 对象的状态不受外界影响
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
缺点
- 无法取消Promise,一旦新建它就会立即执行,无法中途取消(优点就是不受外界因素影响)
- 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
- 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
14.2 基本用法 ###
ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。
// Promise构造函数接受一个函数作为参数,// 该函数的两个参数分别是resolve和reject。它们是两个函数,// 由 JavaScript 引擎提供,不用自己部署。const promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作成功 */){ resolve(value); } else { reject(error); }});
Promise实例生成以后,可以用then方法分别指定resolved状态(成功)和rejected状态(失败)的回调函数。
参数二可选,这两个函数都接受Promise对象传出的值作为参数。
promise.then(function(value) { // success}, function(error) { // failure});
异步加载图片例子
function loadImageAsync(url) { return new Promise(function(resolve, reject) { const image = new Image(); image.onload = function() { resolve(image); }; image.onerror = function() { reject(new Error('Could not load image at ' + url)); }; image.src = url; });}
Ajax 操作的例子。
const getJSON = function(url) { const promise = new Promise(function(resolve, reject){ const handler = function() { if (this.readyState !== 4) { return; } if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } }; const client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler; client.responseType = "json"; client.setRequestHeader("Accept", "application/json"); client.send(); }); return promise;};getJSON("/posts.json").then(function(json) { console.log('Contents: ' + json);}, function(error) { console.error('出错了', error);});
如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数
reject函数的参数通常是Error对象实例
resolve函数的参数除正常值外还可以是Promise实例
14.3 Promise.prototype.then()
作用:
为 Promise 实例添加状态改变时的回调函数。
参数:
.then(参数1, 参数2), then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。
(理解成: 一个成功回调函数,一个失败回调函数,而失败回调函数是可选的)
返回值:
一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
getJSON("/posts.json").then(function(json) { return json.post;}).then(function(post) { // ...});//这里应该有三个Promise实例//getJSON本身是一个,返回json.post是一个,第二个then方法也是一个Promise实例
code
getJSON("/post/1.json").then(function(post) { return getJSON(post.commentURL);}).then(function funcA(comments) { console.log("resolved: ", comments);}, function funcB(err){ console.log("rejected: ", err);});
用箭头函数写
getJSON("/post/1.json").then( post => getJSON(post.commentURL);).then( comments => console.log("resolved: ", comments);, err => console.log("rejected: ", err););
注
//箭头函数()=>{} (实为一个表达式,而非函数)function foo (a) { console.log(a);}//变成箭头就是const foo = (a) => {console.log(a)}; //return一个表达式的时候才能直接省略在箭头后面function foo (a,b) { let total = a + b; console.log(total);}const foo = (a, b) => { let total = a + b; console.log(total);}
14.4 Promise.prototype.catch()
返回值: Promise 对象
Promise.prototype.catch
方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。
getJSON('/posts.json').then(function(posts) { // ...}).catch(function(error) { // 处理 getJSON 和 前一个回调函数运行时发生的错误 console.log('发生错误!', error);});
举个栗子
const promise = new Promise(function(resolve, reject) { throw new Error('test');});promise.catch(function(error) { console.log(error);});// Error: test
如果 Promise 状态已经变成resolved,再抛出错误是无效的。
const promise = new Promise(function(resolve, reject) { resolve('ok'); throw new Error('test');});promise .then(function(value) { console.log(value) }) .catch(function(error) { console.log(error) });// ok
Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
getJSON('/post/1.json').then(function(post) { return getJSON(post.commentURL);}).then(function(comments) { // some code}).catch(function(error) { // 处理前面三个Promise产生的错误});
// badpromise .then(function(data) { // success }, function(err) { //不要在then中定义reject回调, // error });// goodpromise .then(function(data) { //cb // success }) .catch(function(err) { //建议总是使用catch // error });
catch方法之中,还能再抛出错误。
14.5 Promise.all()
作用
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
p的状态简单的说就是
p1 && p2 && p3 为true时,结果才为true,否则false
// 生成一个Promise对象的数组const promises = [2, 3, 5, 7, 11, 13].map(function (id) { return getJSON('/post/' + id + ".json");});Promise.all(promises).then(function (posts) { // ...}).catch(function(reason){ // ...});
14.6 Promise.race()
Promise.race
方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
Promise.race方法的参数与Promise.all方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。
14.7 Promise.resolve()
作用:
将现有对象转为 Promise 对象
const jsPromise = Promise.resolve($.ajax('/whatever.json'));
Promise.resolve
方法的参数分成四种情况。
(1)参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
(2)参数是一个thenable对象
thenable对象指的是具有then方法的对象,比如下面这个对象
let thenable = { then: function(resolve, reject) { resolve(42); }};
Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
let thenable = { then: function(resolve, reject) { resolve(42); }};let p1 = Promise.resolve(thenable);p1.then(function(value) { console.log(value); // 42});
上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42。
(3)参数不是具有then方法的对象,或根本就不是对象
如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。
const p = Promise.resolve('Hello');p.then(function (s){ console.log(s)});// Hello
上面代码生成一个新的 Promise 对象的实例p。由于字符串Hello不属于异步操作(判断方法是字符串对象不具有 then 方法),返回 Promise 实例的状态从一生成就是resolved,所以回调函数会立即执行。Promise.resolve方法的参数,会同时传给回调函数。
(4)不带有任何参数
Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
所以,如果希望得到一个 Promise 对象,比较方便的方法就是直接调用Promise.resolve方法。
const p = Promise.resolve();p.then(function () { // ...});
上面代码的变量p就是一个 Promise 对象。
需要注意的是,立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。
事件循环是???
setTimeout(function () { console.log('three');}, 0);Promise.resolve().then(function () { console.log('two');});console.log('one');// one// two// three
上面代码中,setTimeout(fn, 0)
在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log(‘one’)则是立即执行,因此最先输出。
14.8 Promise.reject()
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
const p = Promise.reject('出错了');// 等同于const p = new Promise((resolve, reject) => reject('出错了'))p.then(null, function (s) { console.log(s)});// 出错了
注意:
Promise.reject()方法的参数,会原封不动地作为reject的理由(理由? 啥意思),变成后续方法的参数。这一点与Promise.resolve方法不一致。
const thenable = { then(resolve, reject) { reject('出错了'); }};Promise.reject(thenable).catch(e => { console.log(e === thenable)})// true
上面代码中,Promise.reject方法的参数是一个thenable对象,执行以后,后面catch方法的参数不是reject抛出的“出错了”这个字符串,而是thenable对象。
一句话: 出错就抛出原Promise
14.9 两个有用的附加方法(不在ES6之中)
done()
Promise 对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为 Promise 内部的错误不会冒泡到全局)。因此,我们可以提供一个done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。
asyncFunc() .then(f1) .catch(r1) .then(f2) .done();
它的实现代码相当简单。
Promise.prototype.done = function (onFulfilled, onRejected) { this.then(onFulfilled, onRejected) .catch(function (reason) { // 抛出一个全局错误 setTimeout(() => { throw reason }, 0); });};
从上面代码可见,done方法的使用,可以像then方法那样用,提供fulfilled和rejected状态的回调函数,也可以不提供任何参数。但不管怎样,done都会捕捉到任何可能出现的错误,并向全局抛出。
finally()
finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。
下面是一个例子,服务器使用 Promise 处理请求,然后使用finally方法关掉服务器。
server.listen(0) .then(function () { // run test }) .finally(server.stop);
它的实现也很简单。
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => P.resolve(callback()).then(() => value), reason => P.resolve(callback()).then(() => { throw reason }) );};
上面代码中,不管前面的 Promise 是fulfilled还是rejected,都会执行回调函数callback。
14.10 应用
详情见: http://es6.ruanyifeng.com/#docs/promise#应用
14.11 Promise.try()
详情见: http://es6.ruanyifeng.com/#docs/promise#Promise-try
阮老师 ES6标准入门
http://es6.ruanyifeng.com/#docs/promise
- Promise对象——ECMAScript 6 入门笔记(一)
- ECMAScript 6 入门--Promise 对象
- ECMAScript 6 入门笔记(五)异步promise,Generator,async
- 超级厉害的JavaScript —— ECMAScript 6 标准(8) —— Promise对象
- ECMAScript 6 入门 个人笔记(一)
- ECMAScript 6 Promise
- JS 基础 —— ECMAScript 对象 笔记
- ES6对象知识扩展(ECMAScript 6 入门笔记)
- 《ECMAScript 6入门》笔记6
- ECMAScript 6 入门学习笔记
- ECMAScript 6入门 学习笔记
- 《ECMAScript 6入门》笔记1
- 《ECMAScript 6入门》笔记2
- 《ECMAScript 6入门》笔记3
- 《ECMAScript 6入门》笔记4
- 《ECMAScript 6入门》笔记5
- ECMAScript6学习笔记——promise对象
- 《ECMAScript 6入门》——JavaScript
- 『每周观察』:“在线抓娃娃”开启新娱乐窗口
- AV1:为互联网提供开放、免费的视频编解码工具
- using UnityEditor引用注意事项
- linux中fork()函数详解
- windows 安装 mediawiki
- Promise对象——ECMAScript 6 入门笔记(一)
- springmvc或者springboot整合swagger
- python scrapy cannot import name '_win32stdio'的解决办法
- 2017-12-12
- POJ-1511 Invitation Cards
- Android 动画详解(二)之animation组合使用
- AngularJs路由
- webpack 使用心得
- MySQL常用指令