Promise的使用

1. 基本用法

const promise = new Promise(function(resolve, reject)=> {
  if(成功) {
    resolve(value)
  } else{
    reject(error)
  }
})

Promise 构造函数接受一个函数作为它的参数。
该函数有两个内置参数,分别是resolvereject,它们是两个js内置函数。
resolve的作用是把Promise 对象的状态由 pending 变成 resolved。在异步操作成功时调用,把参数返回出去;
reject的作用是把Promise对象的状态由pending 变成 rejected。在异步操作失败时调用,可以把抛出的错误作为参数返回出去。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

Promise 的实例可以用.then方法指定成功和失败状态的回调,也可以分别用.then.catch方法指定成功和失败的回调。

用Promise对象实现的 Ajax :

const getJSON = function(url) {
  return 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();

  });
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出错了', error);
});
  • Promise 新建后就会立即执行;
  • 如果一个异步操作的结果是返回另一个异步操作,内层的状态会逐步传递给外层;
  • resolve或者reject的调用,并不会阻碍后续代码的执行;但是一般情况下状态改变后就不进行别的操作了,所以可以加个return语句;
new Promise((resolve, reject) => {
  resolve(1);
  console.log(2);
}).then(r => {
  console.log(r);
});
// 2
// 1

2. Promise.prototype.then

  • .then方法接收两个回调,这两个回调分别在状态变为resolved时调用和rejected时调用。这两个函数都是可选的,不一定要提供。它们都接受Promise对象传出的值作为参数。
  • .then方法的返回值是一个新的Promise实例,因此可以采用链式调用,前一个方法的返回值会作为后一个.then的参数。后一个会等待前面的状态改变再被调用。
getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function (comments) {
  console.log("resolved: ", comments);
}, function (err){
  console.log("rejected: ", err);
});

3. Promise.prototype.catch

  • .catch()方法,相当于.then(null, rejection).then(undefined, rejection),用于指定发生错误时的回调函数;
  • .then()方法指定的回调函数,如果运行中抛出错误,也会被.catch()方法捕获;
  • .reject()方法的作用,等同于抛出错误:
const promise = new Promise(function(resolve, reject) {
  throw new Error('test');
});
promise.catch(function(error) {
  console.log(error);
});
// Error: test

等同于

const promise = new Promise(function(resolve, reject) {
  reject(new Error('test'));
});
promise.catch(function(error) {
  console.log(error);
});
  • 如果 Promise 状态已经变成 resolved,再抛出错误是无效的。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了:
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语句捕获;
  • 不推荐使用.then()第二个参数来处理失败状态,推荐使用 .catch,因为这种写法可以捕获前面then方法执行中的错误;
  • 如果Promise 对象后没有跟着.catch方法,Promise 对象抛出的错误不会传递到外层代码,不会阻碍进程。
    **

4. Promise.prototype.finally

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。它的参数是一个回调函数,不接受任何参数,执行的操作与状态无关。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

5. Promise.all

  • Promise.all方法接收一个数组或者类数组对象,每一项都是Promise实例,如果不是也会内部转换。
const p = Promise.all([p1, p2, p3]);
  • 只有p1、p2、p3的状态都变成fulfilledp的状态才会变成fulfilledp1、p2、p3的返回值作为数组,传递给p的回调函数;
  • 只要p1、p2、p3之中有一个被rejectedp的状态就变成rejected,第一个被reject的实例的返回值,会传递给p的回调函数;
  • 如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()catch方法。因为它调用了自己的catch,返回了新的 Promise 实例,状态为 resolved,统一传递给Promise.all().then()的回调:
const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result)
.catch(e => e);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]

如果p2没有自己的catch方法,就会调用Promise.all()的catch方法:

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// Error: 报错了

6.Promise.any()

const p = Promise.any([p1, p2, p3]);
  • 只有p1、p2、p3的状态有一个变成fulfilledp的状态就会变成fulfilled,第一个成功的实例的返回值会作为参数传递给回调;
  • 如果p1、p2、p3都变成rejected状态,p的状态就会变成rejectedp1、p2、p3抛出的错误作为数组,传递给p的回调函数;
var resolved = Promise.resolve(42);
var rejected = Promise.reject(-1);
var alsoRejected = Promise.reject(Infinity);

Promise.any([resolved, rejected, alsoRejected]).then(function (result) {
  console.log(result); // 42
});

Promise.any([rejected, alsoRejected]).catch(function (results) {
  console.log(results); // [-1, Infinity]
});

7. Promise.race()

  • Promise.race方法接收一个数组或者类数组对象,每一项都是Promise实例,如果不是也会内部转换。
const p = Promise.race([p1, p2, p3]);
  • 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

8. Promise.allSettled()

  • Promise.allSettled()方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象。
  • 等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled还是rejected),会把结果打包成数组传递给成功的回调:
const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);

const allSettledPromise = Promise.allSettled([resolved, rejected]);

allSettledPromise.then(function (results) {
  console.log(results);
});
// [
//    { status: 'fulfilled', value: 42 },
//    { status: 'rejected', reason: -1 }
// ]
  • results的每个成员是一个对象,对象的格式是固定的:
// 异步操作成功时
{status: 'fulfilled', value: value}

// 异步操作失败时
{status: 'rejected', reason: reason}

9. Promise.resolve()

  • Promise.resolve() 可以将现有对象转为 Promise 对象:
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
  • Promise.resolve()方法的参数分成4种情况:
    (1)参数是一个 Promise 实例:
    这种情况下,Promise.resolve 将不做任何修改、原封不动地返回;
    (2)参数是一个具有then方法的对象:
    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
});

(3)参数不是具有then()方法的对象,或根本就不是对象
Promise.resolve()方法返回一个新的 Promise 对象,状态为resolved,会立即执行.then回调;

const p = Promise.resolve('Hello');

p.then(function (s) {
  console.log(s)
});
// Hello

(4)不带有任何参数
Promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。

const p = Promise.resolve();
p.then(function () {
  // ...
});
  • 立即resolve()Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。
setTimeout(function () { // 在下一轮“事件循环”开始时执行
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');

// one
// two
// three

10. 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)
});
// 出错了

参考文章: ECMAScript 6 入门——promise对象

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容