Promise对象

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Promise对象相关的知识,希望对你有一定的参考价值。

原文地址:https://wangdoc.com/javascript/

概述

Promise对象是javascript的异步操作解决方案,为异步操作提供统一接口。它起到代理作用,充当异步操作与回调函数之间的中介,使得异步操作具备同步操作的接口。Promise可以让异步操作写起来,就像在写同步操作的流程,而不必一层层嵌套回调函数。
首先,Promise是一个对象,也是一个构造函数。

function f1(resolve, reject) {
    // 异步代码
}

var p1 = new Promise(f1);

上面代码中,Promise构造函数接受一个回调函数f1作为参数,f1里面是异步操作的代码。然后,返回的p1就是一个Promise实例。
Promise的设计思想是,所有异步任务都返回一个Promise实例。Promise实例有一个then方法,用来指定下一步的回调函数。

var p1 = new Promise(f1);
p1.then(f2);

上面代码中,f1的异步操作完成,就会执行f2
传统的写法可能需要把f2作为回调函数传入f1,比如写成f1(f2),异步操作完成后,在f1内部调用f2Promise使得f1f2变成了链式写法。不仅改善了可读性,而且对于多层嵌套的回调函数尤其方便。

Promise对象的状态

Promise对象通过自身的状态,来控制异步操作。Promise实例具有三种状态。

  • 异步操作未完成(pending)
  • 异步操作成功(fulfilled)
  • 异步操作失败(rejected)
    上面三种状态里面,fulfilledrejected合在一起称为resolved(已定型)。
    Promise的最终结果只有两种。
  • 异步操作成功,Promise实例传回一个值(value),状态变为fulfilled
  • 异步操作失败,Promise实例抛出一个错误(error),状态变为rejected

    Promise构造函数

var promise = new Promise(function (resolve, reject) {
    if (/* 异步操作成功 */) {
        resolve(value);
    } else { /* 异步操作失败 */
        reject(new Error());
    }
});

上面代码中,Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject。它们是两个函数,由JavaScript引擎提供,不用自己实现。
resolve函数作用是,将Promise实例状态从pending变为fulfilled,在异步调用成功时调用,并将异步调用结果作为参数传递出去。reject函数的作用是,将Promise实例的状态从pending变为rejected,在异步操作失败时调用,并将异步操作报错,作为参数传递出去。
下面是一个例子:

function timeout(ms) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, ms, "done"); // "done"作为参数传入resolve()
    });
}

timeout(100);

上面代码中,timeout(100)返回一个Promise实例。100毫秒以后,该实例的状态会变为fulfilled

Promise.prototype.then()

Promise实例的then方法,用来添加回调函数。
then方法接受两个回调函数,第一个是异步操作成功时(变为fulfilled状态的回调函数),第二个是异步操作失败(变为rejected)时的回调函数(该参数可以省略)。一旦状态改变,就调用相应的回调函数。

var p1 = new Promise(function (resolve, reject) {
    resolve("success");
});
p1.then(console.log, console.error);

var p2 = new Promise(function (resolve, reject) {
    reject(new Error("failed"));
});
p2.then(console.log, console.error);

上面代码中,p1p2都是Promise实例,它们then方法绑定两个回调函数:成功时回调函数console.log,失败时的回调函数console.error(可以省略)。
then方法可以链式调用。

p1.then(step1)
    .then(step2)
    .then(step2)
    .then(console.log, console.error);

上面代码中,p1后面有四个then,意味着依次有四个回调函数。只要前一步的状态变为fulfilled,就会依次执行紧跟着在后面的回调函数。
最后一个then方法,回调函数是console.logconsole.error,用法上有一个重要的区别。console.log只显示step3的返回值,而console.error可以显示p1step1step2step3之中任意一个发生的错误。

then()用法辨析

Promise的用法,简单说就是一句话:使用then方法添加回调函数。
写法一

f1().then(function () {
    return f2();
}).then(f3);

上面代码,f3的参数是f2函数运行的结果。
写法二

f1().then(function () {
    f2();
}).then(f3);

上面代码,f3的参数是undefined
写法三

f1().then(f2()).then(f3);

上面代码,f3的参数是f2函数返回的函数运行的结果。
写法四

f1().then(f2).then(f3);

写法四与写法一只有一个差别,那就是f2会接收到f1()返回的结果。

实例:图片加载

下面是使用Promise完成图片的加载。

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

preloadImage("url").then(function (e) {
    document.body.append(e.target);
}).then(function () {
    console.log(‘加载成功‘); 
});

以上是关于Promise对象的主要内容,如果未能解决你的问题,请参考以下文章

前端面试题之手写promise

前端片段整理

什么时候然后从Promise.all()的子句运行?

ES6 promise对象

JavaScript - Promise对象

Promise对象