浅谈ES6 - Promise

概念:Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值。

语法

new Promise( function(resolve, reject) {...} /* executor */  );

参数
executor
executor是带有 resolve 和 reject 两个参数的函数 。Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor 函数在Promise构造函数返回所建promise实例对象前被调用)。resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。executor 内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改成fulfilled,要么调用reject 函数将promise的状态改为rejected。如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。

描述
Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象
一个 Promise有以下几种状态:
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。
因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回promise 对象, 所以它们可以被链式调用。
Promise工作流程
属性:
Promise.length
length属性,其值总是为 1 (构造器参数的数目).
Promise.prototype
表示 Promise 构造器的原型.

方法:
Promise.all(iterable)

这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。
这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。(可以参考jQuery.when方法—译者注)

Promise.race(iterable)
**当iterable参数里的任意一个子promise被成功或失败后,**父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。

Promise.reject(reason)
返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法

Promise.resolve(value)
返回一个状态由给定value决定的Promise对象。如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(该value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法。通常而言,如果你不知道一个值是否是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value以Promise对象形式使用。

ES5中传统的回调

{
  //Es5
  //基本定义 模拟ajax请求
  let ajax = function(callback) {
    console.log('执行');
    setTimeout(function(){
      //执行回调函数
      callback&&callback.call();
    },1000)
  };
 
  ajax(function(){
    console.log('ES5'+'timeout1');
  });
}

ES6新增的Promise可解决地狱回调

扫描二维码关注公众号,回复: 11608376 查看本文章
{
  //ES6
  let ajax = function() {
    console.log('执行2');
    return new Promise(function(resolve,reject){
      //setTimeout可以看成一个模拟网络等异步执行的函数
      setTimeout(function(){
        resolve();//表示执行下一步(then())
      }, 1000);
    })
  };

  ajax().then(function(){
    console.log('promise','timeout2');
  });
}

Promise实例

{
  let ajax = function() {
    console.log('执行3');
    return new Promise(function(resolve,reject){
      setTimeout(function(){
        resolve();
      }, 3000);
    })
  };

  ajax()
    .then(function(){
      return new Promise(function(resolve,reject){
        setTimeout(function(){
          console.log('2');
          resolve()
        }, 3000);
      });
    })
      .then(function(){
        console.log('timeout3');
        // resolve(); //直接使用会报错 必须在返回Promise对象中才能执行
        return new Promise(function(resolve,reject){
          setTimeout(function(){
            resolve();
          },3000);
        })
    })
    //error 因为如果上一个不是返回Promise对象故resolve()无法执行下面的then()
    .then(function(){
      console.log('4');
    })
    
    //打印结果:执行3  2 timeout3 4
    
}

catch捕获错误:在Promise对象中有两个参数

{
  //catch捕获错误
  let ajax = function(num){
    console.log('执行4');
    return new Promise(function(resolve,reject) {
      if(num > 5){
        resolve();
      }else{
        reject('结果小于5');
      }
    })
  }

  ajax(6)
    .then(function(){
      console.log('log',6); //log 6
    })
    .catch(function(err){
      console.log('catch',err);
    });

  ajax(3)
    .then(function(){
      console.log('log',3);
    })
    .catch(function(err){
      console.log('catch',err); //catch 结果小于5
      ajax(7)
      .then(function(){
        console.log('log',7); // 7
      })
    });
}

Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:

job1.then(job2).then(job3).catch(handleError);
//其中,job1、job2和job3都是Promise对象。

除了串行执行若干异步任务外,Promise还可以并行执行异步任务。
试想一个页面聊天系统,我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是可以并行执行的,用Promise.all()实现如下:

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.all([p1, p2]).then(function (results) {
    console.log(results); // 获得一个Array: ['P1', 'P2']
});

有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
    console.log(result); // 'P1'
});

由于p1执行较快,Promise的then()将获得结果’P1’。p2仍在继续执行,但执行结果将被丢弃
如果我们组合使用Promise,就可以把很多异步任务以并行和串行的方式组合起来执行。

Promise.all()实例 - 所有图片加载完在添加到页面

{
  // 所有图片加载完在添加到页面
  function loadImg(src){
    return new Promise((resolve,reject)=>{
      let img = document.createElement('img');
      img.src = src;
      img.onload = function(){
        resolve(img);
      }
      img.onerror = function(err){
        reject(err);
      }
    })
  }

  function showImgs(imgs){
    imgs.forEach(function(img){
      document.body.appendChild(img);
    })
  }
  //Promise.all() 需等待所有资源加载完成才执行下一步
  Promise.all([
    loadImg('http://localhost:8081/H5test/img/monster1.jpg'),
    loadImg('http://localhost:8081/H5test/img/mario.jpg'),
    loadImg('http://localhost:8081/H5test/img/monster1.jpg')
  ]).then(showImgs);
}

Promise.race()实例 - 有一个图片加载完就添加到页面 其他图片不显示了

{
  // 有一个图片加载完就添加到页面 其他图片不显示了
  function loadImg(src){
    return new Promise((resolve,reject)=>{
      let img = document.createElement('img');
      img.src = src;
      img.onload = function(){
        resolve(img);
      }
      img.onerror = function(err){
        reject(err);
      }
    })
  }
  //创建图片
  function showImgs(img){
    let p = document.createElement('p');
    p.appendChild(img);
    document.body.appendChild(p);
  }
  //Promise.race() 只要其中一个资源先加载完成就只执行该资源对应下一步的操作
  Promise.race([
    loadImg('http://localhost:8081/H5test/img/monster1.jpg'),
    loadImg('http://localhost:8081/H5test/img/mario.jpg'),
    loadImg('http://localhost:8081/H5test/img/monster1.jpg')
  ]).then(showImgs);
}

参考链接:
廖雪峰ES6 Promise
javascript Promise | MDN

猜你喜欢

转载自blog.csdn.net/weixin_43931898/article/details/102755916