ES6 Promise

1》介绍

1.异步编程的一种解决方案
2.简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
3.特点:
1>.对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
2>Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。
只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。
4.Promise 缺点
1>无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2>其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
3>第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

2》基本用法

1.Promise对象是一个构造函数,用来生成Promise实例;构造函数的含有两个函数参数 resolve与reject
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

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

2.Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
then方法可以接受两个回调函数作为参数。
第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。第二个函数是可选的,不一定要提供。
这两个函数都接受Promise对象传出的值作为参数。即调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。

promise.then(function(value) {
  // resolve
}, function(error) {
  // reject
});

function timeout(ms) {
  return new Promise(function(resolve,reject){
    setTimeout(resolve('done'), ms);
  })
}
timeout(100).then(function(value){
  console.log(value)
});

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

var promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});
promise.then(function() {
  console.log('resolved');
});
console.log('Hi!');   //Promise   Hi!   resolved.

4.调用resolve或reject并不会终结 Promise 的参数函数的执行。因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

new Promise((resolve, reject) => {
  resolve(1);
  console.log(2);
}).then(r => {
  console.log(r);
}); //2 1

改进
new Promise((resolve, reject) => {
  return resolve(1);
  // 后面的语句不会执行
  console.log(2);
})

3》Promise.prototype等方法

1.Promise.prototype.then()
链式的then,可以指定一组按照次序调用的回调函数。
这时,前一个回调函数,return有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
promise.then().then()....

2.Promise.prototype.catch()
  <1>Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

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

  <2>如果 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) });

  <3>Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。

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

  <4>Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。

const someAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    // 下面一行会报错,因为x没有声明
    resolve(x + 2);
  });
};
someAsyncThing().then(function() {
  console.log('everything is great');
});
setTimeout(() => { console.log(123) }, 2000);

3.Promise.prototype.finally()

  finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作;且finally方法的回调函数不接受任何参数
  promise.then(result => {···}).catch(error => {···}).finally(() => {···});

  实现:https://github.com/matthew-andrews/Promise.prototype.finally/blob/master/finally.js

4.Promise.all()

  用于将多个 Promise 实例,包装成一个新的 Promise 实例;接受一个数组作为参数 Promise.all([p1, p2, p3]);
  区别:并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调

  https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/130

Promise.all([runAsync1(), runAsync2(), runAsync3()]).then(function(results){
      console.log(results);  
  });

5.Promise.race() 

  用于将多个 Promise 实例,包装成一个新的 Promise 实例接受一个数组作为参数 Promise.all([p1, p2, p3]);
  all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」

  https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/140

function runAsync1(){
      var p = new Promise(function(resolve, reject){
          //做一些异步操作
          setTimeout(function(){
              console.log('异步任务1执行完成');
              resolve('随便什么数据1');
          }, 1000);
      });
      return p;            
    }
    function runAsync2(){
      var p = new Promise(function(resolve, reject){
          //做一些异步操作
          setTimeout(function(){
              console.log('异步任务2执行完成');
              resolve('随便什么数据2');
          }, 2000);
      });
      return p;            
    }
    function runAsync3(){
      var p = new Promise(function(resolve, reject){
          //做一些异步操作
          setTimeout(function(){
              console.log('异步任务3执行完成');
              resolve('随便什么数据3');
          }, 2000);
      });
      return p;            
    }

    Promise.all([runAsync1(), runAsync2(), runAsync3()]).then(function(results){
        console.log(results);
    });

    Promise.race([runAsync1(), runAsync2(), runAsync3()]).then(function(results){
        console.log(results);
    });

6.Promise.resolve()
将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用。
(1)参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
(2)参数是一个thenable对象

  Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
  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方法的对象,或根本就不是对象
  如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。

const p = Promise.resolve('Hello');
      p.then(function (s){
      console.log(s)
});// Hello

(4)不带有任何参数
  Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
  需要注意的是,立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。

setTimeout(function () {
  console.log('three'); //下一轮“事件循环”开始时执行
}, 0);
Promise.resolve().then(function () {
  console.log('two'); //本轮“事件循环”结束时执行
});
console.log('one'); // one   two   three

7.Promise.reject()

  Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
  参数用法同上
  const p = Promise.reject('出错了');
  // 等同于
  const p = new Promise((resolve, reject) => reject('出错了'))

8.Promise.try()
  让同步函数同步执行,异步函数异步执行

4》案例:

  案例1:

const promise = new Promise((resolve, reject) => {
    console.log(1);
    resolve();
    console.log(2);
})

promise.then(() => {
    console.log(3);
})

console.log(4);

  首先 Promise 新建后立即执行,所以会先输出 1,2,而 Promise.then() 内部的代码在 当次 事件循环的 结尾 立刻执行 ,所以会继续输出4,最后输出3。

案例2:

  

const promise = new Promise((resolve, reject) => {
    resolve('success1');
    reject('error');
    resolve('success2');
});

promise.then((res) => {
    console.log('then:', res);
}).catch((err) => {
    console.log('catch:', err);
})

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

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

       而一旦状态改变,就不会再变。所以 代码中的reject('error'); 不会有作用。

  Promise 只能 resolve 一次,剩下的调用都会被忽略。所以 第二次的 resolve('success2'); 也不会有作用。因此:then: success1

案例3:

Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)

  Promise.resolve 方法的参数如果是一个原始值,或者是一个不具有 then 方法的对象,则 Promise.resolve 方法返回一个新的 Promise 对象,状态为resolved,Promise.resolve 方法的参数,会同时传给回调函数。

  then 方法接受的参数是函数,而如果传递的并非是一个函数,它实际上会将其解释为 then(null),这就会导致前一个 Promise 的结果会穿透下面。因此:1

 

原文地址:https://www.cnblogs.com/changxue/p/8393107.html