PWA(Progressive Web App)入门系列:(四)Promise

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lecepin/article/details/78948408

前言

这一章说一下ES6的Promise对象。为什么要在PWA系列的文章中讲Promise呢?因为PWA中的许多技术API中都是以Promise返回的方式返回的,为了对后续章节中PWA技术API更好的理解,这里就来说一个Promise对象。

Promise出现的背景

在JavaScript当中,处理异步操作时,我们需要知道操作是否已经完成,当执行完成的时候会返回一个回调函数,表示操作已经完成。所以在处理异步操作时,通常是使用回调嵌套的方式(CallBack)。但是如果出现多层回调嵌套,也就是我们常说的回调金字塔(Pyramid of Doom),绝对是一种糟糕的编程体验。

像这样:

function a1() {
  function a2() {
    function a3() {
      function a4() {
        function a5() {
          ...
        }
      }
    }
  }
}

回调方式主要会导致两个关键问题:

  1. 嵌套太深代码可读性太差
  2. 行逻辑必须串行执行。

在这种情况下,Promise 对象出现了。2015 年 6 月,加入了ECMAScript 6 的标准。

Promise简介

Promise 对象用于一个异步操作的最终完成(或失败)及其结果值的表示。一个 Promise 对象代表一个目前还不可用,但是在未来的某个时间点可以被解析的值。它允许你以一种同步的方式编写异步代码。Promises 将嵌套的回调改造成一系列的.then的链式调用,去除了层层嵌套的劣式代码风格。Promises 不是一种解决具体问题的算法,而已一种更好的代码组织模式。

上面的代码,用Promise的方式可以写成:

a1.then(function(data) {
  return a2(data)
})
.then(function(data) {
  return a3(data)
})
.then(function(data) {
  return a4(data)
})
.then(function(data) {
  return a5(data)
})
...

Promise 对象有以下两个特点

  1. 对象的状态不受外界影响。 Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)、 Rejected(已失败)。根据异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是“承诺”,表示无法通过其他手段改变。
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。 Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。

Promise状态:



语法

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

executor是一个带有 resolvereject 两个参数的函数 。executor 函数在Promise构造函数执行时同步执行,被传递 resolvereject 函数(executor 函数在Promise构造函数返回新建对象前被调用)。resolvereject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。executor 内部通常会执行一些异步操作,一旦完成,可以调用resolve函数来将promise状态改成fulfilled,或者在发生错误时将它的状态改为rejected。
如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。

基本用法

new Promise(function(resolve, reject) {
  // ... some code

  if (/* 操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

注意:实例化的Promise对象会立即执行



方法

下面说一下Promise对象的方法。

Promise.prototype.then()

then方法是定义在原型对象Promise.prototype上的。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。

then方法返回的是一个新的Promise实例。因此可以采用链式写法,即then方法后面再调用另一个then方法。

Promise.prototype.catch()

catch() 方法返回一个Promise,只处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。用于指定发生错误时的回调函数。

taskkA()
.then(function() {
  return taskB()
})
.then(function() {
  return taskC()
})
.catch(function(err) {
  // ...
})
.then(function() {
  return taskD()
})



Promise.resolve()

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

Promise.resolve(value)
Promise.resolve(promise)
Promise.resolve(thenable)

有时需要将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用。

Promise.resolve('data')
// 等价于
new Promise(resolve => resolve('data'))

Promise.reject()

返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法。该实例的状态为rejected。

var p = Promise.reject('出错了');
// 等同于
var p = new Promise((resolve, reject) => reject('出错了'))

p.catch(function(err) {
  console.log(err)
})
// 出错了

Promise.all()

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

Promise.all(iterable)

iterable: 一个可迭代对象,例如一个 Array 或 String。

上述可迭代对象中的所有 Promise 被 resolve 之后返回 resolve,或者在任一 Promise 被 reject 后返回 reject。

Promise.race()

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

用法和Promise.all()类似。

Promise.race(iterable);

基本应用

下面根据Promise的特性,做几个例子。

异步加载图片

function loadImage(url) {
  return new Promise(function(resolve, reject) {
    var img= new Image();

    img.onload = function() {
      resolve(img);
    };

    img.onerror = function(err) {
      reject(new Error(err));
    };

    img.src = url;
  });
}

网络请求超时处理

Promise.race([
  fetch('http://xxxx.xxx'),
  new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('请求超时')), 6000)
  })
]).
then(function(data) {
  // ...
})
.catch(function(err) {
  // 处理错误...
})

总结

这一篇里,对Promise的背景由来,及相关方法进行了相应的介绍说明,也了解到了Promise在异步处理上的使用优势。


博客名称:王乐平博客

CSDN博客地址:http://blog.csdn.net/lecepin

知识共享许可协议
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。

猜你喜欢

转载自blog.csdn.net/lecepin/article/details/78948408