【promise】什么是promise?

一、介绍

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
在这里插入图片描述

  • 一个对象,用来处理异步操作。使异步操作写的更优雅、更易于阅读。
  • 从字面上理解,promise是承诺、许诺的意思。意思是使用promise后,不管成功还是失败肯定会有返回值。
    • promise有三种状态:pending(进行中),resolved(完成),rejected(失败),只有异步返回的结构可以改变其状态。所以,promise的过程一般只有两种:pending->resolved或者pending到rejected。
    • promise对象还有一个比较常用的then方法,用来执行回调函数,then方法接受两个参数
Promise.prototype.then(resolved,rejected)
var Pro = function (time) {
        //返回一个Promise对象
        return new Promise(function (resolve, reject) {
                console.log('123');
                //模拟接口调用
                setTimeout(function () {     //这里告诉Promise 成功了,然后去执行then方法 的第一个函数
                        resolve('成功返回');
                        }, time);
                    })
                };
        (function(){
            console.log('start');
            Pro(3000)
            .then(function(data){
                    console.log(data);
                    return Pro(5000);})
            .then(function(data){
                    console.log(data);
                    console.log('end');
                })
        })();

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。
在这里插入图片描述

Promise 新建后就会立即执行
let promise = new Promise(function(resolve, reject) {
    console.log('Promise');
    resolve();});

    promise.then(function() {
        console.log('resolved.');
    });
}

console.log('Hi!');
// Promise
// Hi!
// resolved

上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。

Promise回调地域

回调地域,其实简单来说就是异步回调函数的嵌套。存在异步任务的代码,不能保证能按照顺序执行。

setTimeout(function () {  //第一层
    console.log(111);
    setTimeout(function () {  //第二程
        console.log(222);
        setTimeout(function () {   //第三层
            console.log(333);
        }, 1000)
    }, 2000)
}, 3000)

解决方法

解决回调地域的办法是,利用promise.then方法将异步操作的结果按照顺序执行,catch方法用来接收处理失败时相应的数据。在上一个promise.then方法中,返回下一个promise对象

//1.封装一个函数 :  根据文件名生成  文件读取的promise
function getPromise(fileName) {
    let p = new Promise((resolve, reject) => {
        //读文件
        fs.readFile(`./data/${fileName}.txt`, 'utf-8', (err, data) => {
            if (err == null) {
                //成功
                resolve(data);
            } else {
                //失败
                reject(err);
            }
        });
    });
    return p;
};

//2.解决需求: 要先读a, 读完a后读b, 读完b后读c.

//开始读取a
getPromise('a').then((data)=>{
    console.log(data);
    //继续读取b
    return getPromise('b');
}).then((data)=>{
    console.log(data);
    //继续读取c
    return getPromise('c');
}).then((data)=>{
    console.log(data);
}).catch((err)=>{
    //以上三个异步操作,只要有任何一个出错,都会执行err
    console.log(err);
});

Promise.prototype.finally()
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。

promise.then(result => {··})
.catch(error => {··})
.finally(() => {··});

上面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数

Promise.all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.all([p1, p2, p3]);

上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

Promise.race()

Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.race([p1, p2, p3]);

上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。Promise.race()方法的参数与Promise.all()方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。

二、应用场景
  • 请求超时提醒、接口重试实现(刷新token)
  • 同时拉取多个接口,将多个请求结果合并到一起(微信小程序登录)
  • 异步加载图片

我们可以将图片的加载写成一个Promise,一旦加载完成,Promise的状态就发生变化。

const preloadImage = function (path) {
  return new Promise(function (resolve, reject) {
    const image = new Image();
    image.onload  = resolve;
    image.onerror = reject;
    image.src = path;
  });};

在这里插入图片描述

Promise.try()

实际开发中,经常遇到一种情况:不知道或者不想区分,函数f是同步函数还是异步操作,但是想用 Promise 来处理它。因为这样就可以不管f是否包含异步操作,都用then方法指定下一步流程,用catch方法处理f抛出的错误。一般就会采用下面的写法。

Promise.resolve().then(f)

上面的写法有一个缺点,就是如果f是同步函数,那么它会在本轮事件循环的末尾执行。

const f = () => console.log('now');
Promise.resolve().then(f);
console.log('next');
// next
// now

上面代码中,函数f是同步的,但是用 Promise 包装了以后,就变成异步执行了。那么有没有一种方法,让同步函数同步执行,异步函数异步执行,并且让它们具有统一的 API 呢?回答是可以的,并且还有两种写法。第一种写法是用async函数来写。

const f = () => console.log('now');
(async () => f())();
console.log('next');
// now
// next

上面代码中,第二行是一个立即执行的匿名函数,会立即执行里面的async函数,因此如果f是同步的,就会得到同步的结果;如果f是异步的,就可以用then指定下一步,就像下面的写法。(async () => f())().then(…)需要注意的是,async () => f()会吃掉f()抛出的错误。所以,如果想捕获错误,要使用promise.catch方法。

(async () => f())().then(...).catch(...)
第二种写法是使用
new Promise()const f = () => console.log('now');(
  () => new Promise(
    resolve => resolve(f())
  ))();
console.log('next');
// now
// next

上面代码也是使用立即执行的匿名函数,执行new Promise()。这种情况下,同步函数也是同步执行的。鉴于这是一个很常见的需求,所以现在有一个提案,提供Promise.try方法替代上面的写法。

const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next

事实上,Promise.try存在已久,Promise 库Bluebird、Q和when,早就提供了这个方法。由于Promise.try为所有操作提供了统一的处理机制,所以如果想用then方法管理流程,最好都用Promise.try包装一下。这样有许多好处,其中一点就是可以更好地管理异常。

function getUsername(userId) {
  return database.users.get({id: userId})
  .then(function(user) {
    return user.name;
  });}

上面代码中,database.users.get()返回一个 Promise 对象,如果抛出异步错误,可以用catch方法捕获,就像下面这样写。database.users.get({id: userId}).then(…).catch(…)但是database.users.get()可能还会抛出同步错误(比如数据库连接错误,具体要看实现方法),这时你就不得不用try…catch去捕获。

try {
  database.users.get({id: userId}).then(...)
  .catch(...)} catch (e) {
// ...
}

上面这样的写法就很笨拙了,这时就可以统一用promise.catch()捕获所有同步和异步的错误。

Promise.try(() => database.users.get({id: userId}))
  .then(...)
  .catch(...)

事实上,Promise.try就是模拟try代码块,就像promise.catch模拟的是catch代码块。留言

三、promise一些特性
  • promise新建后就会立即执行
  • promise.then的回调函数中,可以返回一个新的promise
  • 对于一个已经向后台获取数据已经产生结果的promise:p1,再次调用p1.then,不会去重新发起请求获取数据
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Joseph365

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值