promise对象

(1)“promise”是一个对象或者函数,该对象或者函数有一个then方法;
(2)“thenable”是一个对象或者函数,用来定义then方法;
(3)“value”是promise状态成功时的值;
(4)“reason”是promise状态失败时的。

promise状态

异步操作有三种状态:pending(进行中),fulfilled(已成功),rejected(已失败)

状态改变,只可以pending-->fulfilled, pending-->rejected变化;只有处于fulfilled,rejected,状态就不会变化了,即resolved(已定型)

状态的缺点

无法取消promise,一旦新建,就会立即执行,无法中途取消。

如果不设置回调函数,promise内部抛出的错误,不会反映到外部。

当处于pending 时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

避免了层层嵌套的回调函数,解决回调地狱

 基本用法:

1.promise是一个构造函数,用来生成promise的实例

接受一个函数作为参数,

const promise = new Promise(function(resolve,reject){
    //...some code
    if(异步操作成功){
        resolve(value);    
    }else{
        reject(error);
    }
})

Promise 构造函数接受一个函数作参数,两个参数:resolve和reject,它们由js引擎提供,不用自己部署。

resolve函数作用,将promise对象的状态从“未完成”变成“成功”(pending-->resolved),在异步操作对象成功时调用,并将异步操作的结果作为参数传出去。

reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

promise实例生成以后,用then方法分别指定resolved和rejected的回调函数。

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

then方法

then方法接受两个函数作为参数,第一个是promise 执行成功的回调,第二个是失败时的回调,两个函数只会有一个被调用。

Promise新建后会立即执行

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved

上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。

异步加载图片

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;
  });
}

上面代码中,使用Promise包装了一个图片加载的异步操作。如果加载成功,就调用resolve方法,否则就调用reject方法。

Promise对象实现的 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);
});

上面代码中,getJSON是对 XMLHttpRequest 对象的封装,用于发出一个针对 JSON 数据的 HTTP 请求,并且返回一个Promise对象。需要注意的是,在getJSON内部,resolve函数和reject函数调用时,都带有参数。

如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例,比如像下面这样。

const p1 = new Promise(function (resolve, reject) {
  // ...
});

const p2 = new Promise(function (resolve, reject) {
  // ...
  resolve(p1);
})

上面代码中,p1p2都是 Promise 的实例,但是p2resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。

这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。

then 方法的特点

在 JavaScript 事件队列的当前运行完成之前,回调函数永远不会被调用。

const p = new Promise(function(resolve,reject){
  resolve('success');
});
 //回调函数就是被作为参数传递的函数
p.then(function(value){
  console.log(value);
});
 
console.log('first');
// first
// success

promise.prototype.then()

then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。

通过.then形式添加的回调函数,不论什么时候,都会被调用。通过多次调用.then,可以添加多个回调函数,他们会按照插入顺序并且独立运行。

const p = new Promise(function(resolve,reject){
  resolve(1);
}).then(function(value){ // 第一个then // 1
  console.log(value);
  return value * 2;
}).then(function(value){ // 第二个then // 2
  console.log(value);
}).then(function(value){ // 第三个then // undefined
  console.log(value);
  return Promise.resolve('resolve'); 
}).then(function(value){ // 第四个then // resolve
  console.log(value);
  return Promise.reject('reject'); 
}).then(function(value){ // 第五个then //reject:reject
  console.log('resolve:' + value);
}, function(err) {
  console.log('reject:' + err);
});

最后一个为什么执行reject:reject?

 
上一个return的是一个 promise 状态是reject
所以在下一个then里面 走的是 reject的

then 方法将返回一个resolved或rejected状态的promise对象对于链式调用,且promise对象的值就是这个返回值。

Promise.prototype.catch()

        用于指定发生错误时的回调函数。一般来说不要在then方法中定义rejected状态的回调函数,而应多使用catch方法。

        promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获位置。错误总会被下一个catch语句捕获。

        catch返回的还是一个Promise对象。

Promise.all()

        用于将多个promise实例包装成一个新的Promise实例。状态由参数(都是Promise对象的实例)决定,都为resolved才是resolved,or 是rejected.

        如果参数自身定义了catch(), 那么rejected的时候不会触发Promise.all()的catch()方法

        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 => console.log(result))
        .catch(e => console.log(e))
        Promise.all([p1,p2])
        .then(result => console.log(result)) // [hello,undefined]
        .catch(e => console.log(e));
        //如果作为参数的Promise实例自身定义了catch方法,那么它被rejected的时候不会触发Promise.all()的catch方法
        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 => console.log(result))
        Promise.all([p1,p2])
        .then(result => console.log(result))
        .catch(e => console.log(e)); //Error: 报错了

注意点:

注意要返回或终止Promise链

大多数浏览器不能终止promise链中的rejection,建议后面跟上.catch(error => console.log(error));

来源:《阮一峰ES6》,菜鸟教程

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值