美文网首页
Promise对象

Promise对象

作者: 撕心裂肺1232 | 来源:发表于2018-08-30 19:06 被阅读0次

    1.概述

    在JavaScript中,所有的代码都是单线程执行的,由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。Promise 对象是 JavaScript 的异步操作解决方案,为异步操作提供统一接口。Promise起到代理(proxy)的作用,使得异步操作具备同步操作的接口,Promise 可以让异步操作写起来,就像在写同步操作的流程,而不必一层层地嵌套回调函数。
    异步执行可以调用回调函数实现:

    function callback() {
        console.log('Done');
    }
    console.log('before setTimeout()');
    setTimeout(callback, 1000); // 1秒钟后调用callback函数
    console.log('after setTimeout()');
    
    //控制台输出结果:
    before setTimeout()
    after setTimeout()
    (等待1秒后)
    Done
    

    简单地说,异步操作会在将来的某个事件点触发一个函数调用。
    ajax是典型的异步操作。以上一节的代码为例:

    request.onreadystatechange = function () {
        if (request.readyState === 4) {
            if (request.status === 200) {
                return success(request.responseText);
            } else {
                return fail(request.status);
            }
        }
    }
    

    首先,Promise 是一个对象,也是一个构造函数。

    function f1(resolve, reject) {
      // 异步代码...
    }
    
    var p1 = new Promise(f1);
    

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

    // Promise
    function f1(){
    ...
    }
    var p1 = new Promise(f1);
    p1.then(f2);

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

    step1(function (value1) {
      step2(value1, function(value2) {
        step3(value2, function(value3) {
          step4(value3, function(value4) {
            // ...
          });
        });
      });
    });
    
    // Promise 的写法
    (new Promise(step1))
      .then(step2)
      .then(step3)
      .then(step4);
    

    2.Promise 对象的状态

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

    • 异步操作未完成(pending)
    • 异步操作成功(fulfilled)
    • 异步操作失败(rejected)

    状态变化:

    • 未完成 to 成功
    • 未完成 to 失败

    Promise的最终结果:

    • 异步操作成功,Promise 实例传回一个值(value),状态变为fulfilled。
    • 异步操作失败,Promise 实例抛出一个错误(error),状态变为rejected。

    3.Promise 构造函数

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

    4. .then()

    var p1 = new Promise(function (resolve, reject) {
      resolve('成功');
    });
    p1.then(console.log, console.error);
    // "成功"
    
    var p2 = new Promise(function (resolve, reject) {
      reject(new Error('失败'));
    });
    p2.then(console.log, console.error);
    // Error: 失败
    

    then()的用法:

    f1().then(function () {            
      return f2();
    }).then(f3);
    
    //f3回调函数的参数,是f2函数的运行结果。
    
    f1().then(function () {
      f2();
      return;
    }).then(f3);
    
    //f3回调函数的参数是undefined
    
    f1().then(f2())
      .then(f3);
    
    //f3回调函数的参数,是f2函数返回的函数的运行结果
    
    f1().then(f2)
      .then(f3);
    
    //f2会接收到f1()返回的结果,f3回调函数的参数,是f2函数的运行结果。
    

    5. Promise的优势

    Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了:


    promise.png

    Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
    串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:

    job1.then(job2).then(job3).catch(handleError);
    

    除了串行执行若干异步任务外,Promise还可以并行执行异步任务
    例如一个页面聊天系统,我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是可以并行执行的用 Promise.all()实现

    var p1 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 500, 'P1');
    });
    var p2 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 600, 'P2');
    });
    // 同时执行p1和p2,并在它们都完成后执行then:
    Promise.all([p1, p2]).then(function (results) {
        console.log(results); // 获得一个Array: ['P1', 'P2']
    });
    

    有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:

    var p1 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 500, 'P1');
    });
    var p2 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 600, 'P2');
    });
    Promise.race([p1, p2]).then(function (result) {
        console.log(result); // 'P1'
    });
    
    //由于p1执行较快,Promise的then()将获得结果'P1'。p2仍在继续执行,但执行结果将被丢弃。
    

    传送门

    相关文章

      网友评论

          本文标题:Promise对象

          本文链接:https://www.haomeiwen.com/subject/lazlwftx.html