异步编程Promise探究

“回调地狱”是一种前端开发常见的问题现象,为了解决这一问题,ES6引入了Promise,什么是Promise ?具体如何使用?本文将会针对这些问题进行分析,对Promise进行探究。

一、回调地狱

存在异步的两个方法A和B,而B的执行需要依据A执行完毕后的结果,B此时就是A的回调函数,如果涉及的异步执行方法很多,A->B->C->D....,就会产生所谓的“回调地狱”现象。举例说明如下:

function ajaxDemo(){
  $.ajax({
    type : "POST",
    url : "",
    data : {
    },
    success : function(resultA) {
      //根据resultA做一些业务判断,参数转化等
      $.ajax({
        type : "POST",
        url : "",
        data : {
        },
        success : function(resultB) {
          //根据resultB做一些业务判断,参数转化等
          $.ajax({
            type : "POST",
            url : "",
            data : {
            },
            success : function(resultC) {
              //根据resultC做一些业务判断,参数转化等
              //...........
            }
          });
        }
      });
    }
  });
}

这样就会造成代码可读及维护性很差,接下来要说的Promise是怎么解决这种问题的。

二、Promise是什么

在介绍Promise之前,先了解一下javascript异步编程发展历史:

1、当一个JavaScript应用在运行的时候,它会以单线程的方式运行,这样避免了开发人员为多线程编程中可能出现的棘手问题而担心。
2、不过这种自由是有条件的:为了写出能够流畅运行的软件,必须考虑异步,而不仅仅是用户输入。
3、JavaScript对异步编程的支持有三个不同的阶段:回调(callback)阶段、promise(承诺)阶段和生成器(generator)阶段。
4、生成器本身并不提供任何对异步的支持:它们依赖于承诺或特定类型的回调来提供异步行为。同样,像承诺这样有用的东西,会依赖于回调(而回调本身又由于具有对象而变得更有用)。

摘自:《JavaScript学习指南(第3版)》【美】Ethan Brown

从上述文字中,可以知道无论是回调还是承诺,都是javascript异步编程的一种方式,而且承诺会依赖回调,这也让我们明白:技术的发展是有相关性的,不能独立看待。

那Promise是什么?

Promise是JavaScript第一个标准的异步模型,包含传递信息与状态的对象,拥有以下两个特点:
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有3种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

摘自:《JavaScript框架设计(第2版)》司徒正美

摘取书中“http请求”代码案例:

function get(url) {
  return new Promise(function(resolve, reject){
    var req = new XMLHttpRequest();    
    req.open('GET',url);    
    req.onload = function() {
      if (req.status == 200) {
        resolve(req.response);      
      }else {
        reject(Error(req.statusText));      
      }    
    };
    req.onerror = function() {      
      reject(Error("Network Error"));    
    };
    req.send();  
  });
}

get('story.json').then(function(response) {  
    console.log("Success!", response);
  },function(error) {  
    console.error("Failed!", error);
});

这个案例清晰的介绍了Promise的实现思路:Promise构造httpGet请求,get('story.json')进入Pending状态,运行结果成功变成Resolved状态,调用resolve方法;运行结果失败或者异常时调用进入Rejected状态调用reject方法。

三、Promise使用

这一部分将会例举Promise几种常用使用方式:

  • 链式使用 Promise
const fetchPromise = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');

fetchPromise
  .then( response => {
    return response.json();
  })
  .then( json => {
    console.log(json[0].name);
  });
  • 异常捕获
const fetchPromise = fetch('bad-scheme://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');

fetchPromise
  .then( response => {
    if (!response.ok) {
      throw new Error(`HTTP 请求错误:${response.status}`);
    }
    return response.json();
  })
  .then( json => {
    console.log(json[0].name);
  })
  .catch( error => {
    console.error(`无法获取产品列表:${error}`);
  });
  • 合并使用多个Promise
const fetchPromise1 = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
const fetchPromise2 = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found');
const fetchPromise3 = fetch('https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json');

Promise.all([fetchPromise1, fetchPromise2, fetchPromise3])
  .then( responses => {
    for (const response of responses) {
      console.log(`${response.url}:${response.status}`);
    }
  })
  .catch( error => {
    console.error(`获取失败:${error}`)
  });
  • async 和 await
async function fetchProducts() {
  try {
    const response = await fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
    if (!response.ok) {
      throw new Error(`HTTP 请求错误:${response.status}`);
    }
    const json = await response.json();
    return json;
  }
  catch(error) {
    console.error(`无法获取产品列表:${error}`);
  }
}

const jsonPromise = fetchProducts();
jsonPromise.then((json) => console.log(json[0].name));

代码示例摘自:如何使用 Promise - 学习 Web 开发 | MDN

Promise分析的就到这里,希望对你有所帮助。

猜你喜欢

转载自blog.csdn.net/siweidetu/article/details/127044243
今日推荐