详解js的Promise

Promise

Promise是异步编程的一种解决方案,它比传统的解决方案--回调函数和事件--更合理且更加强大,它最早是由社区提出并实现,后面ES6将其写进了语言标准,统一了用法,也提供了Promise。

特点
  1. 对象的状态不受外界影响(3中状态)

(1) Pending状态(进行中)
(2) Fulfilled状态(已成功)
(3) Rejected状态(已失败)

  1. 一旦状态改变就不会再发生变化(两种状态改变:成功或失败)

(1) Pending(进行中) -> Fulfilled(已成功)
(2) Pending(进行中) -> Rejected(已失败)

用法

创建Promise实例
const promise = new Promise(function(resolve, reject) {
    if (/*异步操作成功*/) {
        resolve(value)
    } else {
        reject(error)
    }
})
  • Promise构造函数接受一个函数作为参数,该函数接受两个参数,分别是resolve和reject,它们是两个函数,是由javascript引擎提供,不用自己部署。
  • resolve作用是将Promise对象状态由‘未完成’变为‘成功’,也就是Pending -> Fulfilled,在异步操作成功时调用,并将异步操作的结果作为参数传递出去,而rejected函数则是将Promise对象状态由‘未完成’变为‘失败’,也就是Pending -> Rejected,在异步操作失败时调用,并将异步操作的结果作为参数传递出去。
Promise的方法
  1. then,这个方法是定义在原型对象Promise.prototype上的,它的作用是为Promise实例添加状态改变时的回调函数。它返回的是一个新的Promise实例,注意,不是原来的那个Promise实例,因此可以采用链式写法,即then方法后面再调用一个then方法。
    Promise实例生成后,可用then方法分别指定两种状态回调函数,then方法可用接受两个回调函数作为参数:
    (1) Promise对象状态改为Resolved时调用(必须)
    (2) Promise对象状态改为Rejected时调用(可选)
    (3) 基本用法:
function sleep(ms) {
    return new Promise(function(resolve, reject) {
        setTimeout(resolve, ms);
    })
}
sleep(500).then( ()=> console.log("finished"));

这段代码定义了一个函数sleep,调用后,等待了指定参数(500)毫秒后执行then中的函数。值得注意的是,Promise新建后就会立即执行。

catch方法。这个方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

getJSON('/posts.json').then(function(posts) {
  // ...
}).catch(function(error) {
  // 处理 getJSON 和 前一个回调函数运行时发生的错误
  console.log('发生错误!', error);
});

上面代码中,getJSON方法返回一个Promise对象,如果该对象状态变为resolved,则会调用then方法指定的回调函数,如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误,另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。

p.then((val) => console.log('fulfilled:', val))
  .catch((err) => console.log('rejected', err));

// 等同于
p.then((val) => console.log('fulfilled:', val))
  .then(null, (err) => console.log("rejected:", err));

下面一个例子

const promise = new Promise(function(resolve, reject) {
  throw new Error('test');
});
promise.catch(function(error) {
  console.log(error);
});
// Error: test

上面代码中,promise抛出一个错误,就被catch方法指定的回调函数捕获,注意,上面的写法与下面的两种写法时等价的。

// 写法一
const promise = new Promise(function(resolve, reject) {
  try {
    throw new Error('test');
  } catch(e) {
    reject(e);
  }
});
promise.catch(function(error) {
  console.log(error);
});

// 写法二
const promise = new Promise(function(resolve, reject) {
  reject(new Error('test'));
});
promise.catch(function(error) {
  console.log(error);
});

如果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在resolve语句后面,再抛出错误,不会被捕获,等于没有抛出,因为Promise的状态一旦改变,就永久的保持该状态,不会再发生变化。
Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止,也就是说,错误总是会被下一个catch语句捕获。

getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 处理前面三个Promise产生的错误
});

上面代码中,一共有三个Promise对象:一个是由getJSON产生,另外两个是由then产生,它们之中有任何一个抛出错误,都会被最后一个catch捕获。
一般来说,不要在then方法里面定义Reject状态的回调函数(即then的第二个参数)就使用catch方法

// bad
promise
  .then(function(data) {
    // success
  }, function(err) {
    // error
  });

// good
promise
  .then(function(data) { //cb
    // success
  })
  .catch(function(err) {
    // error
  });

上面的代码中,第二种写法要好于第一种写法,因为第二种写法可以捕获前面then方法执行中的错误,也更接近同步的写法(try/catch)。因此,建议总是使用catch方法,而不使用then方法的第二个参数。

你可能感兴趣的:(详解js的Promise)