资讯专栏INFORMATION COLUMN

Promise对象

琛h。 / 2671人阅读

摘要:对比回调函数和暂时不管是什么,先看一下下面的代码,看一看的好处。回调函数执行一次首先,定义一个回调函数,调用一次,看看这个代码的写法。上面的代码中,在方法中需要传递两个回调函数,这样看着会有点乱。

对比回调函数和Promise

暂时不管Promise是什么,先看一下下面的代码,看一看Promise的好处。需要特别说明的是,在这个对比的中,Promise和回调都没有考虑存在异常的情况。

回调函数执行一次

首先,定义一个回调函数,调用一次,看看这个代码的写法。

"use strict";

// 定义一个计数器,用来统计回调函数执行的次数
let count = 1;

/**
 * 定义一个异步执行函数,参数是回调函数
 */
function asyncFunc(callback) {
  setTimeout(function () {
    callback(`callback ... 执行了 ${count} 次`);
    count++;
  }, 1000);
};

// 调用函数
asyncFunc(function(data){
  console.log(data);
});

/*************************************
callback ... 执行了 1 次
*************************************/

如果用Promise改写,会是什么样的效果呢?

"use strict";

// 定义一个计数器,用来统计回调函数执行的次数
let count = 1;

/**
 * 定义一个异步执行函数,返回值是一个Promise对象
 */
function asyncFunc() {
  let promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve(`resolve ... 执行了 ${count} 次`);
      count++;
    }, 1000);
  });
  return promise;
};

// 调用函数
asyncFunc().then(function(data){
  console.log(data);
});

/*************************************
resolve ... 执行了 1 次
*************************************/

怎么感觉代码更复杂,更加难于理解了?确实,在定义函数的时候,需要返回一个Promise对象,增加了代码量,看着没什么优势。从这点来看,学这个东西,完全没有必要啊。

别着急,接着往下走。。。。

回调函数执行多次

上面的情况只是调用一次函数,那么调用多次呢?比如调用个五次、七次。下面咱们看看调用七次的情况。

首先,还是先看看使用回调函数的情况:

"use strict";

// 定义一个计数器,用来统计回调函数执行的次数
let count = 1;

/**
 * 定义一个异步执行函数,参数是回调函数
 */
function asyncFunc(callback) {
  setTimeout(function () {
    callback(`callback ... 执行了 ${count} 次`);
    count++;
  }, 1000);
};

// 调用函数
asyncFunc(function (data) { // 第一次调用
  console.log(data);
  asyncFunc(function (data) { // 第二次调用
    console.log(data);
    asyncFunc(function (data) { // 第三次调用
      console.log(data);
      asyncFunc(function (data) { // 第四次调用
        console.log(data);
        asyncFunc(function (data) { // 第五次调用
          console.log(data);
          asyncFunc(function (data) { // 第六次调用
            console.log(data);
            asyncFunc(function (data) { // 第七次调用
              console.log(data);
            });
          });
        });
      });
    });
  });
});

/*************************************
callback ... 执行了 1 次
callback ... 执行了 2 次
callback ... 执行了 3 次
callback ... 执行了 4 次
callback ... 执行了 5 次
callback ... 执行了 6 次
callback ... 执行了 7 次
*************************************/

看着挺好看,但是,当回调更多的时候,如何分清是哪个回调,又怎么判断哪个括号对应哪句代码呢?其实这就是一个回调地狱,这样的代码可读性差。

这个时候,Promise就可以发挥作用了。

看了回调函数,再来看看使用Promise的情况:

"use strict";

// 定义一个计数器,用来统计回调函数执行的次数
let count = 1;

/**
 * 定义一个异步执行函数,返回值是一个Promise对象
 */
function asyncFunc() {
  let promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve(`resolve ... 执行了 ${count} 次`);
      count++;
    }, 1000);
  });
  return promise;
};

// 调用函数
asyncFunc() // 第一次调用
  .then(function (data) {
    console.log(data);
    return asyncFunc(); // 第二次调用
  })
  .then(function (data) {
    console.log(data);
    return asyncFunc(); // 第三次调用
  })
  .then(function (data) {
    console.log(data);
    return asyncFunc(); // 第四次调用
  })
  .then(function (data) {
    console.log(data);
    return asyncFunc(); // 第五次调用
  })
  .then(function (data) {
    console.log(data);
    return asyncFunc(); // 第六次调用
  })
  .then(function (data) {
    console.log(data);
    return asyncFunc(); // 第七次调用
  })
  .then(function (data) {
    console.log(data);
  });
  
/*************************************
resolve ... 执行了 1 次
resolve ... 执行了 2 次
resolve ... 执行了 3 次
resolve ... 执行了 4 次
resolve ... 执行了 5 次
resolve ... 执行了 6 次
resolve ... 执行了 7 次
*************************************/

会发现,是用了Promise代码可读性变得很好,以后也便于修改。

用Promise包装旧回调写法

现在可以看出Promise的好处,如果想以后都使用Promise,可否实现?

肯定可以实现啊,下面就使用Promise来包装上面的回调函数。

使用Promise包裹的时候,只需要经过下面几个步骤:

定义一个函数,返回Promise对象

在Promise对象中调用异步执行函数,参数是创建Promise对象时传递的函数

"use strict";

// 定义一个计数器,用来统计回调函数执行的次数
let count = 1;

/**
 * 定义一个异步执行函数,参数是回调函数
 */
function asyncFunc(callback) {
  setTimeout(function () {
    callback(`callback ... 执行了 ${count} 次`);
    count++;
  }, 1000);
};

/**
 * 包装异步执行函数,返回一个Promise对象
 */
function wrapperAsyncFunc() {
  let promise = new Promise(function (resolve, reject) {
    asyncFunc(resolve);
  });
  return promise;
};

// 调用
wrapperAsyncFunc()
  .then(function (data) {
    console.log(data);
    return wrapperAsyncFunc();
  })
  .then(function (data) {
    console.log(data);
  });
  
/*************************************
callback ... 执行了 1 次
callback ... 执行了 2 次
*************************************/
认识Promise

在谷歌浏览器中,我们看看Promise都包含什么:

方法概述

可以看到,在Promise的prototype上有三个方法,也就是实例对象上有三个方法:

new Promise(function(resolve, reject) { ... } );
promise.then(onFulfilled[, onRejected]);
promise.catch(onRejected);

Promise对象本身的方法,就是静态方法:

Promise.all(iterable);
Promise.race(iterable);
Promise.reject(reason);
Promise.resolve();
Promise的三种状态

在认识这些方法之前,先认识一下Promise的三种状态:

pending: 初始状态,创建Promise成功后的状态

fulfilled: 操作执行成功后的状态

rejected: 操作执行失败后的状态

Promise的实例方法

首先,先来创建一个Promise对象,可以根据num的值,来调节执行的函数是resolve还是reject:

new Promise(function(resolve, reject) { ... } );
"use strict";

let num = 3;

// 创建一个Promise对象
let promise = new Promise(function (resolve, reject) {
  if (num > 5) {
    resolve("success ..."); // 操作执行成功执行的函数
  } else {
    reject("failure ..."); // 操作执行失败执行的函数
  }
});

首先明确一点,Promise对象创建的时候,立即执行。可是,既然是立即执行,怎么获取对应的状态值呢?下面就要使用then方法了。

promise.then(onFulfilled[, onRejected]);
promise.then(function (data) {
  console.log(data);
}, function (reason) {
  console.log(reason);
});

上面的代码中,在then方法中需要传递两个回调函数,这样看着会有点乱。有没有更优的解决方式?有,这个时候要使用catch方法。

// 把上面的代码进行简化
promise
  .then(function (data) { // 状态变为fulfilled后执行的回调
    console.log(data);
  }).catch(function (reason) { // 状态变为rejected后执行的回调
    console.log(reason);
  });
Promise的静态方法

为了方法认识Promise.all和Promise.race,定义三个Promise对象:

let promise1 = new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve("promise1 ...");
    console.log("done1 ...");
  }, 2000); // 延迟2秒
});

let promise2 = new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve("promise2 ...");
    console.log("done2 ...");
  }, 4000); // 延迟4秒
});

let promise3 = new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve("promise3 ...");
    console.log("done3 ...");
  }, 6000); // 延迟6秒
});
Promise.all

Promise.all的作用是在参数中的所有Promise对象完全执行完成的时候,才会执行自身的then或catch方法:

Promise
  .all([promise1, promise2, promise3])
  .then(function (data) {
    console.log(data);
  })
  .catch(function (reason) {
    console.log(reason);
  });
 
/***************************************
done1 ...
done2 ...
done3 ...
[ "promise1 ...", "promise2 ...", "promise3 ..." ]
***************************************/

Promise.all中所有的Promise对象状态都变为fulfiled状态时,才会触发then方法;其中一个变为rejected状态,那么就触发catch方法。

需要注意的是,即使触发了catch方法,其他的Promise对象中的代码还是会正常执行的。因为这是Promise的特性,创建之后,立即执行。

更改一个Promise对象之后,结果就会成下面的状态:

let promise2 = new Promise(function (resolve, reject) {
  setTimeout(function () {
    reject("promise2 ...");
    console.log("done2 ...");
  }, 4000);
});

/***************************************
done1 ...
done2 ...
promise2 ...
done3 ...
***************************************/
Promise.race

Promise.race的作用是在参数中的Promise对象中的一个执行完成的时候,就会执行自身的then或catch方法:

Promise
  .race([promise1, promise2, promise3])
  .then(function (data) {
    console.log(data);
  })
  .catch(function (reason) {
    console.log(reason);
  });

/***************************************
done1 ...
promise1 ...
done2 ...
done3 ...
***************************************/

需要注意的是:Promise.all方法是所有的都执行完成才会触发then方法,就是不落下任何一个人;而Promise.race方法是有一个执行完成就会触发then方法,就是看谁跑得快。

后续的两个方法,以后用到的时候再补充,因为这些内容对现在而言已经够用了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88977.html

相关文章

  • Promise——从阅读文档到简单实现(一)

    摘要:意味着操作成功完成。方法接收失败情况的回调函数作为参数,返回一个对象。参数回调函数不接收任何参数,当对象变成状态时被调用。现在各个方法的参数返回值功能和使用方法已经有个大概的了解了,为了进一步理解其原理,接下来我打算简单地实现一下它。 前言 最近几周参加笔试面试,总是会遇到实现异步和处理异步的问题,然而作者每次都无法完美地回答。在最近一次笔试因为 Promise 而被刷掉后,我终于下定...

    yanwei 评论0 收藏0
  • 关于Promise

    摘要:反之,操作失败,对象由状态转换为状态,此时回调函数会执行方法。这里需要注意的是,虽然在之后便执行了方法,但是并不是意味着往后的对象不执行了,其他的还是对象还是要执行的,只是不会再调用函数。 在 掘金上看见一篇写promise的文章,感觉作者写的很棒,文章链接在这:八段代码彻底掌握 Promise 。看完之后感觉学到了很多,所以又重新把JavaScript Promise迷你书(中文版)...

    546669204 评论0 收藏0
  • js-Promise

    摘要:总结用方法创建对象用或添加对象的处理函数它的作用是为实例添加状态改变时的回调函数。方法是的别名,用于指定发生错误时的回调函数。 一、为什么需要Promise Javascript 采用回调函数(callback)来处理异步编程。从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的回调金字塔(Pyramid of Doom),绝对是一种糟糕的编程体验。于是...

    xcold 评论0 收藏0
  • 简单学习 Promise 对象

    摘要:方法是的别名,用于指定发生错误时的回调函数。由于字符串不属于异步操作判断方法是字符串对象不具有方法,返回实例的状态从一生成就是,所以回调函数会立即执行。出错了等同于出错了出错了上面的代码生成一个对象的实例,状态为,回调函数会立即执行。 引言 Promise 是异步编程的一种解决方案,比传统的解决方案——回调和事件——更合理且强大。最近的项目要用到这个,就参照阮一峰老师的《ES6标准入门...

    muzhuyu 评论0 收藏0
  • 尝试实现一个Promise

    摘要:的实现说明没有执行里的函数说明执行了里的函数说明执行里的函数过程中出现错误和执行状态时的回调函数后返回的结果都需要执行传进来的对象不能等于当前的对象回调返回的值或者的值是对象时需要等待该对象的状态变更设置当前状态的状态和值执行回调队列里的函 function resolve_promise_value(promise,value) {//PromiseA+的实现 var th...

    DTeam 评论0 收藏0
  • 关于promise的小结

    摘要:则是把类似的异步处理对象和处理规则进行规范化,并按照采用统一的接口来编写,而采取规定方法之外的写法都会出错。这个对象有一个方法,指定回调函数,用于在异步操作执行完后执行回调函数处理。到目前为止,已经学习了创建对象和用,方法来注册回调函数。 Promise 本文从js的异步处理出发,引入Promise的概念,并且介绍Promise对象以及其API方法。 js里的异步处理 可以参考这篇文章...

    Tony_Zby 评论0 收藏0

发表评论

0条评论

琛h。

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<