Javascript中Promise到底是什么以及结合实例弄清楚

已收录   阅读次数: 710
2021-10-3111:29:47 发表评论
摘要

在学习Vue.js的过程中,肯定会需要用到Promise,即使不使用Vue.js,也会在其他应用场景中使用它,尤其是涉及到各种大型项目的时候,这时候就要搞明白,它是什么,以及如何去使用它了,本篇文章尽量用简短的语言和事例将它讲的清清楚楚……

分享至:
Javascript中Promise到底是什么以及结合实例弄清楚

开篇寄语

在学习Vue.js的过程中,肯定会需要用到Promise,即使不使用Vue.js,也会在其他应用场景中使用它,尤其是涉及到各种大型项目的时候,这时候就要搞明白,它是什么,以及如何去使用它了,本篇文章尽量用简短的语言和事例将它讲的清清楚楚。

内容详情

先来搞清楚Promise这个概念,什么是Promise?根据MDN文档的解释,翻译成中文大意是Promise 对象表示异步操作的最终完成(或失败)及其结果值。

可能看起来不太直观,让咱们转换成具体的事例,即需要向服务器请求获得数据,示例如下:

$.ajax({
    success:function(){
        ...
    }
})

如果碰到嵌套网络请求,例如第一次网络请求成功后回调函数再次发送网络请求,这种代码就会让人很难受,示例如下:

$.ajax({
    success:function(){
	$.ajax({
            ...
        })
    }
})

或者下面这样的写法:

$.ajax({                                                               
     success: function(data)          
     {   
        ...
     },
    complete: function (data) {
        $.ajax({
            success: function(data){
              ...
            }
        })  
    }
});

那么问题来了,如果嵌套越来越多该如何是好?所以这个时候Promise就发挥出来了它应有的作用了,Promise的基本例子,请参看下方示例:

let promise = new Promise(function(resolve, reject) {    
    ...
});

执行函数有两个参数,resolve 和 reject。这些是 JavaScript 语言提供的回调。当调用该函数,该函数在创建新 Promise时自动运行,获得这两个参数值。

为了使Promise有效,执行程序函数应该调用回调函数中的一个,resolve 或 reject。

新的 Promise() 构造函数返回一个 promise 对象。由于Promise函数需要处理异步操作,返回的promise对象应该能够通知执行何时开始、完成(已解决)或因错误而重新调整(拒绝)。

一个 promise 对象具有以下内部属性:

  • state
    • pending
    • fulfilled
    • rejected
  • result
    • undefined
    • value
    • error

这些内部属性是代码不可访问的,但它们是可检查的。这意味着我们将能够使用调试器工具检查状态和结果属性值,但我们将无法使用程序直接访问它们。

如下所示:

Javascript中Promise到底是什么以及结合实例弄清楚

Promise的状态可以是pending、fulfilled或被rejected。resolved或被rejected的promise被称为已解决。

来一个实际例子:

new Promise((resolve, reject) => {
    resolve("succeed");
})

以上的例子就是Promise的简单应用,调试结果如下:

Javascript中Promise到底是什么以及结合实例弄清楚

如果再放入比如reject或者更多的resolve也只是执行第一个resovle而已,其他都会被忽略。

处理Promise的方法有如下几种:

  • .then()
  • .catch()
  • .finally()

分别来说一下它们的使用方法。

  • .then()
    • 应在 promise 对象上调用 .then() 方法来处理result(解决)或error(拒绝)。
let promise = new Promise(function(resolve, reject) {    
});

promise.then(
  (result) => { 
     console.log(result);
  },
  (error) => { 
     console.log(error);
  }
);

当然,也可以选择调用只有一种结果。

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

但是,这只是限定于得到result,如果是error的话,则需要下面的写法:

promise.then(
  null,
  (error) => { 
      console.log(error)
  }
);

不过,.catch()方法可以更好的处理出现的错误,后面会说到。

先来看个实际例子,集合宝可梦的公开API,来查看各种宠物小精灵的信息,实例如下:

function getPromise(URL) {
  let promise = new Promise(function (resolve, reject) {
    let req = new XMLHttpRequest();
    req.open("GET", URL);
    req.onload = function () {
      if (req.status == 200) {
        resolve(req.response);
      } else {
        reject("There is an Error!");
      }
    };
    req.send();
  });
  return promise;
}

获得50个宝可梦信息:

const ALL_POKEMONS_URL = 'https://pokeapi.co/api/v2/pokemon?limit=50';

let promise = getPromise(ALL_POKEMONS_URL);

const consumer = () => {
    promise.then(
        (result) => {
            console.log({result}); // Log the result of 50 Pokemons
        },
        (error) => {
            // As the URL is a valid one, this will not be called.
            console.log('We have encountered an Error!'); // Log an error
    });
}

consumer();

如果只需要选择错误,可以参看使用.catch()方法的下方内容:

let promise = getPromise(POKEMONS_BAD_URL);

const consumer = () => {
    promise.catch(error => console.log(error));
}

consumer();

说了.then和.catch()后,接下来就轮到.finally()了。

.finally()

.finally() 处理程序执行清理操作,例如停止加载程序、关闭实时连接等。无论承诺是解决还是拒绝,都将调用 finally() 方法。它将结果或错误传递给下一个可以再次调用 .then() 或 .catch() 的处理程序。

let loading = true;
loading && console.log('Loading...');

// Gatting Promise
promise = getPromise(ALL_POKEMONS_URL);

promise.finally(() => {
    loading = false;
    console.log(`Promise Settled and loading is ${loading}`);
}).then((result) => {
    console.log({result});
}).catch((error) => {
    console.log(error)
});

除了以上三种方法,还有以下6种方法:

  • Promise.all
  • Promise.any
  • Promise.allSettled
  • Promise.race
  • Promise.resolve
  • Promise.reject

Promise.all

设想有这样一种情况,一个业务需要请求2个地方(A和B)的数据,只有A和B的数据都拿到才能走到下一步。试举例如下:

Promise.all([
    new Promise((resolve, reject) => {
        setTimeout(() => { //  请求A
            resolve('结果A')
        }, 1000)
    }),
    new Promise((resolve, reject) => {
        setTimeout(() => { //  请求B
            resolve('结果B')
        }, 1000)
    })
]).then(results => {
    console.log(results)
})

Promise.any

Promise.any([promises]) - 与 all() 方法类似,.any() 也接受一组 promise 以并行执行它们。此方法不会等待所有承诺都解决。当任何一个承诺得到解决时,它就会完成。

Promise.any([
    new Promise((resolve, reject) => {
        setTimeout(() => { //  请求A
            resolve('结果A')
        }, 1000)
    }),
    new Promise((resolve, reject) => {
        setTimeout(() => { //  请求B
            resolve('结果B')
        }, 1000)
    })
]).then(results => {
    console.log(results)
})

Promise.allSettled()

romise.allSettled([promises]) - 此方法等待所有Promise解决(解决/拒绝)并将其结果作为对象数组返回。结果将包含状态(已完成/已拒绝)和值(如果已完成)。在拒绝状态的情况下,它将返回错误原因。

Promise.allSettled([promise_1, promise_2, promise_3]).then(result => {
    console.log({result});
}).catch(error => {
    console.log('There is an Error!');
});

Promise.race()

Promise.race([promises]) – 它等待第一个(最快的)promise 解决,并相应地返回结果/错误。

Promise.race([promise_1, promise_2, promise_3]).then(result => {
    console.log(JSON.parse(result));
}).catch(error => {
    console.log('An Error Occured');
});

Promise.resolve/reject

Promise.resolve(value) - 它使用传递给它的值来解析一个Promise。它与以下内容相同:

let promise = new Promise(resolve => resolve(value));

Promise.reject(error) – 它拒绝传递给它的错误的promise。它与以下内容相同:

let promise = new Promise((resolve, reject) => reject(error));

以上就是Promise的基本用法了,想必大家已经对此有所掌握了,那么后续在使用Vue.js制作大型项目时会游刃有余许多。

  • 我的微信
  • 微信扫一扫加好友
  • weinxin
  • 我的微信公众号
  • 扫描关注公众号
  • weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: