转载请注明出处:

  Promise 对象是 JavaScript 的异步操作解决方案,为异步操作提供统一接口。它起到代理作用(proxy),充当异步操作与回调函数之间的中介,使得异步操作具备同步操作的接口。Promise 可以让异步操作写起来,就像在写同步操作的流程,而不必一层层地嵌套回调函数。

promise是一种异步解决方案。

  由于ajax异步方式请求数据时,我们不能知道数据具体回来的事件,所以过去只能将一个callback函数传递给ajax封装的方法,当ajax异步请求完成时,执行callback函数。
  promise对象接受resolve和reject两个参数,当一个异步动作发生时,promise对象会通过resolve完成对动作成功进行解析,reject会捕获这个动作的异常。一个promise对象,通过new Promise().then()执行下一步骤操作。
  axios is a promise based HTTP client for the browser and node.js。也就是说,使用axios发出请求,难免涉及promise
  Promise构造函数的参数是一个函数,函数里面的代码是异步的,即Promise里面的操作,和Promise()外面的操作时异步"同时"进行的。Promise中的函数的第一个参数是回调函数,resolve用来触发then里面的代码,第二个参数是回调函数,reject用来触发catch中的代码,throw new Error();也可以触发catch,

  • resolve和reject是两个回调函数,调用resolve会触发then,reject会触发catch
<script>
new Promise((resolve, reject) =>{
setTimeout(() =>{
//成功的时候调用resolve
resolve('成功data')
//失败的时候调用reject
reject('error message')
}, 1000)
}).then((data) =>{
//处理成功后的逻辑
console.log(data);//这个data 是接收的resolve参数--
}).catch((err) =>{
console.log(err);
})
</script>

Promise 链式编程方式比较

  传统的链式调用编程如下:

// 传统写法
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// ...
});
});
});
});

  使用 Promise 之后,可以简化为如下:

// Promise 的写法
(new Promise(step1))
.then(step2)
.then(step3)
.then(step4);

  从上面代码可以看到,采用 Promises 以后,程序流程变得非常清楚,十分易读。注意,为了便于理解,上面代码的​​Promise​​实例的生成格式,做了简化

Promise 对象的状态

  Promise 对象通过自身的状态,来控制异步操作。Promise 实例具有三种状态。

    异步操作未完成(pending)
    异步操作成功(fulfilled)
    异步操作失败(rejected)
  上面三种状态里面,fulfilled和rejected合在一起称为resolved(已定型)。

  这三种的状态的变化途径只有两种。

    从“未完成”到“成功”
    从“未完成”到“失败”
  一旦状态发生变化,就凝固了,不会再有新的状态变化。这也是 Promise 这个名字的由来,它的英语意思是“承诺”,一旦承诺成效,就不得再改变了。这也意味着,Promise 实例的状态变化只可能发生一次。

  因此,Promise 的最终结果只有两种。

  异步操作成功,Promise 实例传回一个值(value),状态变为fulfilled。
  异步操作失败,Promise 实例抛出一个错误(error),状态变为rejected。

Promise 构造函数

  JavaScript 提供原生的​​Promise​​构造函数,用来生成 Promise 实例。

var promise = new Promise(function (resolve, reject) {
// ...

if (/* 异步操作成功 */){
resolve(value);
} else { /* 异步操作失败 */
reject(new Error());
}
});

  上面代码中,Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己实现。

  resolve函数的作用是,将Promise实例的状态从“未完成”变为“成功”(即从pending变为fulfilled),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。reject函数的作用是,将Promise实例的状态从“未完成”变为“失败”(即从pending变为rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
  下面是一个例子。

function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done');
});
}

timeout(100)

  上面代码中,​​timeout(100)​​​返回一个 Promise 实例。100毫秒以后,该实例的状态会变为​​fulfilled​​。

Promise.prototype.then()

   Promise 实例的​​then​​方法,用来添加回调函数。

​  then​​​方法可以接受两个回调函数,第一个是异步操作成功时(变为​​fulfilled​​​状态)时的回调函数,第二个是异步操作失败(变为​​rejected​​)时的回调函数(该参数可以省略)。一旦状态改变,就调用相应的回调函数。

var p1 = new Promise(function (resolve, reject) {
resolve('成功');
});
p1.then(console.log, console.error);
// "成功"

var p2 = new Promise(function (resolve, reject) {
reject(new Error('失败'));
});
p2.then(console.log, console.error);
// Error: 失败

  上面代码中,p1和p2都是Promise 实例,它们的then方法绑定两个回调函数:成功时的回调函数console.log,失败时的回调函数console.error(可以省略)。p1的状态变为成功,p2的状态变为失败,对应的回调函数会收到异步操作传回的值,然后在控制台输出。

  then方法可以链式使用。

p1.then(step1)
.then(step2)
.then(step3)
.then(
console.log,
console.error
);

  上面代码中,p1后面有四个then,意味依次有四个回调函数。只要前一步的状态变为fulfilled,就会依次执行紧跟在后面的回调函数。

  最后一个then方法,回调函数是console.log和console.error,用法上有一点重要的区别。console.log只显示step3的返回值,而console.error可以显示p1、step1、step2、step3之中任意一个发生的错误。举例来说,如果step1的状态变为rejected,那么step2和step3都不会执行了(因为它们是resolved的回调函数)。Promise 开始寻找,接下来第一个为rejected的回调函数,在上面代码中是console.error。这就是说,Promise 对象的报错具有传递性。

小结  

  Promise 的优点在于,让回调函数变成了规范的链式写法,程序流程可以看得很清楚。它有一整套接口,可以实现许多强大的功能,比如同时执行多个异步操作,等到它们的状态都改变以后,再执行一个回调函数;再比如,为多个回调函数中抛出的错误,统一指定处理方法等等。

  而且,Promise 还有一个传统写法没有的好处:它的状态一旦改变,无论何时查询,都能得到这个状态。这意味着,无论何时为 Promise 实例添加回调函数,该函数都能正确执行。所以,你不用担心是否错过了某个事件或信号。如果是传统写法,通过监听事件来执行回调函数,一旦错过了事件,再添加回调函数是不会执行的。

  Promise 的缺点是,编写的难度比传统写法高,而且阅读代码也不是一眼可以看懂。你只会看到一堆then,必须自己在then的回调函数里面理清逻辑。

ES6 学习链接

  ​https://es6.ruanyifeng.com/#docs/promise​