美文网首页
深入解析 Promise 的行为

深入解析 Promise 的行为

作者: demonly | 来源:发表于2017-07-09 22:01 被阅读0次

    属性和方法

    Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。
    Promise 有两个内置属性,[[PromiseStatus]] 和 [[PromiseValue]]。

    • [[PromiseStatus]]:Promise 对象的状态,这个属性可以为三个值:resolved、pending 和 rejected,状态一旦改变为 resolved 或者 rejected 就不能够再变回 pending,resolved 和 rejected 也不能够互相转化。
    • [[PromiseStatus]]:是 Promise 的值,这个值为传入 resolve() 方法和 reject() 方法中的参数。

    Promise 对象有两个方法,then 方法和 catch 方法。

    • then():可以接受两个回调函数作为参数。第一个回调函数在 Promise 对象的状态变为 resolved 时调用,第二个回调函数在 Promise 对象的状态变为 rejected 时调用。这两个函数都接受 [[PromiseStatus]] 作为参数。
    • catch():.then(null, rejection) 的别名,用于指定发生错误时的回调函数。

    Promise 构造函数的方法:

    • Promise.resolve():接受一个参数,创建一个新的 Promise 对象,[[PrmiseStatus]] 为 resolved,[[PromiseValue]] 为传入的参数。
    • Promise.reject():类似 Promise.resolve()。
    • Promise.all():接受一个数组作为参数,将其中的多个 Promise 对象包装成一个新的 Promise 对象。如果数组中某个元素不是 Promise 对象,那么将这个参数传入 Promise.resolve() 方法转换为 Promise 对象。只要有一个 Promise 对象的状态变为 rejected,新 Promise 状态就会立刻变为 rejected,只有当所有的 Promise 对象状态都变为 resolved 时,新 Promise 对象的状态才会变为 resolved。
    • Promise.race():类似 Promise.all,只要有一个 Promise 对象的状态变为 resolved,新 Promise 状态就会立刻变为 resolved,只有当所有的 Promise 对象状态都变为 rejected 时,新 Promise 对象的状态才会变为 rejected。

    基本用法

    new Promise((resolve, reject) => {
        if (condition) {
            resolve(data)
        } else {
            reject(err)
        }
    })
    .then((data) => {
        //do something
        }, (err) => {
        //do something  
        })
    

    值与状态的传递

    下面讨论一些特殊情况下值与状态的传递。

    链式调用

    .then() 方法和 .catch() 方法都会返回一个新的 Promise 对象,这个对象与原 Promise 对象是不同的。

    如果 .then() 方法和 .catch() 方法没有对 Promise 的事件进行处理,那么新的 Promise 将会继承原 Promise 对象的 [[PromiseStatus]] 和 [[PromiseValue]]。
    例如以下代码将会打印 1。第一个 then() 没有对事件进行任何处理,因此第二个 then() 可以拿到原 Promise 传出的 1。

    new Promise((resolve, reject) => {
      reject(1);
    })
    .then(() => {})
    .then(() => {},
          (n) => {console.log(n);});
    

    如果 .then() 方法和 .catch() 方法对事件进行了处理,那么新的 Promise 对象 [[PromiseStatus]] 将会是 resolved,[[PromiseValue]] 将会是 undefined。

    传入 Promise 作为参数

    当 resolve() 方法或者 reject() 方法传入的参数为一个 Promise 对象时会等待其中这个 Promise 对象的状态改变,然后才返回。返回的 Promise 对象的 [[PromiseStatus]] 和 [[PromiseValue]] 都与内层 Promise 相同。例如以下代码将在一秒后打印 '1 reject'。

    new Promise((resolve, reject) => {
      resolve(
        new Promise((resolve, reject) => {setTimeout(() => {reject(1);}, 1000);})
      );
    })
    .then((e) => {console.log(e + ' resolve');},
          (e) => {console.log(e + ' reject');});
    

    需要注意的是,上文说的“等待其中这个 Promise 对象的状态改变”并不是真的说代码会停止在 resolve 处不再执行,实际上代码会继续向下执行并且暂时返回一个状态为 pending 的 Promise 对象,等待状态的改变。例如以下代码将立即打印 2,然后再一秒后打印 '1 reject'

    new Promise((resolve, reject) => {
      resolve(
        new Promise((resolve, reject) => {setTimeout(() => {reject(1);}, 1000);})
      );
          //↓
      console.log(2);
          //↑
    })
    .then((e) => {console.log(e + ' resolve');},
          (e) => {console.log(e + ' reject');});
    

    resolve()方法和 reject() 方法只能够调用一次

    前文说到 Promise 的状态只能够改变一次,实际上是 resolve() 方法和 reject() 方法只能够调用一次。例如:

    new Promise((resolve, reject) => {
      resolve(
        new Promise(
                                  //↓
            () => {setTimeout(() => {reject(1);}, 1000);}
                                  //↑
        )
      );
    })
    .then((e) => {console.log(e + ' resolve');},
          (e) => {console.log(e + ' reject');});
    
    

    这段代码不会打印任何内容,这段代码与前一段的不同之处在于箭头处调用的 reject() 方法是外层 Promise 的 reject() 方法。由于先调用了 resolve() 方法,所以这个 reject() 方法是无效的,另外,resolve() 方法又在等待内部的 Promise 改变状态。因此这个 Promise 对象会一直处于 pending 状态。

    Promise.all() 和 Promise.race()

    以 Promise.all() 为例,Promise.race() 反之。

    resolved

    只要有一个 Promise 对象调用 reject(),新 Promise 状态就会立刻变为 rejected,返回的 [[PromiseValue]] 为最先调用 reject 方法的 [[PromiseValue]]。例如以下代码将会立刻打印 [object Promise] reject,然后报错。

    Promise.all([
      new Promise((resolve, reject) => {
        setTimeout(() => {reject(1);}, 1000);
      }),
      
      new Promise((resolve, reject) => {
        setTimeout(() => {resolve(2);}, 2000);
      }),
      new Promise((resolve, reject) => {
                                                                //↓
        reject(new Promise((resolve, reject) => {setTimeout(() => {reject(3)}, 5000);}));
                                                                //↑
      })
    ]).then((n) => {console.log(n + ' resolve');}, (n) => {console.log(n + ' reject');});
    

    第三个 Promise 的 reject() 方法中传入的 Promise 对象的回调函数依然会被执行,但是 .all() 方法并不会等待内部 Promise 的状态改变,而是直接将返回的 Promise 对象的状态改为 rejected。而且内部 Promise 的状态也不会被传出来,而是因为没有处理而抛出错误。同理,将箭头处的 reject 改为 resolve,打印的依然会立刻打印 [object Promise] reject。再同理,以下代码依然会立刻打印 [object Promise] reject。

    Promise.all([
      new Promise((resolve, reject) => {
        setTimeout(() => {reject(1);}, 1000);
      }),
      new Promise((resolve, reject) => {
        setTimeout(() => {resolve(2);}, 2000);
      }),
      new Promise((resolve, reject) => {
        reject(new Promise((resolve, reject) => {resolve(3)}));
      })
    ]).then((n) => {console.log(n + ' resolve');}, (n) => {console.log(n + ' reject');});
    

    rejected

    只有当内部所有的 Promise 都调用了 resolve() 方法时,返回的 Promise 才会将状态改变为 resolved,其 [[PromiseValue]] 为所有 [[PromiceValue]] 组成的数组。例如以下代码将在 5 秒后打印 [1, 2, 3]。

    Promise.all([
      new Promise((resolve, reject) => {
        setTimeout(() => {resolve(1);}, 1000);
      }),
      new Promise((resolve, reject) => {
        setTimeout(() => {resolve(2);}, 2000);
      }),
      new Promise((resolve, reject) => {
        setTimeout(() => {resolve(3);}, 5000);
      })
    ]).then((n) => {console.log(n);}, (n) => {console.log(n);});
    

    而对于传入 Promise 对象作为参数的情况处理方式又有不同,外部 Promise 对象会等待内部的 Promise 对象状态全部改变为 resolved,之后才会改变状态为 resolved。例如以下代码将在 5 秒后打印 '3 reject'。虽然 resolve() 方法已经被调用了,但是还是会等待它的状态改变。

    Promise.all([
      new Promise((resolve, reject) => {
        setTimeout(() => {resolve(1);}, 1000);
      }),
      new Promise((resolve, reject) => {
        setTimeout(() => {resolve(2);}, 2000);
      }),
      new Promise((resolve, reject) => {
        resolve(new Promise((resolve, reject) => {setTimeout(() => {reject(3)}, 5000);}));
      })
    ]).then((n) => {console.log(n + ' resolve');}, (n) => {console.log(n + ' reject');});
    

    相关文章

      网友评论

          本文标题:深入解析 Promise 的行为

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