学习使用Promise

前言

最近在开发中遇到一个问题:Table行内有下拉组件四级联动,并且还能够添加新行,每一个新行又是四级联动,问:如何解决?想了半天因而使用Promise解决,让我从新对Promise有了认识。javascript

Promise详解

经过MDN 官方文档对Promise有段介绍:Promise 对象用于表示一个异步操做的最终完成 (或失败)及其结果值。html

一个 Promise 对象表明一个在这个 promise 被建立出来时不必定已知的值。它让您可以把异步操做最终的成功返回值或者失败缘由和相应的处理程序关联起来。 这样使得异步方法能够像同步方法那样返回值:异步方法并不会当即返回最终的值,而是会返回一个 promise,以便在将来某个时候把值交给使用者。java

一个 Promise 必然处于如下几种状态之一:ios

  • 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled): 意味着操做成功完成。
  • 已拒绝(rejected): 意味着操做失败。

待定状态的 Promise 对象要么会经过一个值被兑现(fulfilled),要么会经过一个缘由(错误)被拒绝(rejected)。当这些状况之一发生时,咱们用 promise 的 then 方法排列起来的相关处理程序就会被调用。若是 promise 在一个相应的处理程序被绑定时就已经被兑现或被拒绝了,那么这个处理程序就会被调用,所以在完成异步操做和绑定处理方法之间不会存在竞争状态。es6

由于 Promise.prototype.then 和 Promise.prototype.catch 方法返回的是 promise, 因此它们能够被链式调用。axios

image.png
一、构造函数segmentfault

Promise()
建立一个新的 Promise 对象。该构造函数主要用于包装尚未添加 promise 支持的函数。api

二、静态方法数组

Promise.all(iterable)
这个方法返回一个新的promise对象,该promise对象在iterable参数对象里全部的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则当即触发该promise对象的失败。这个新的promise对象在触发成功状态之后,会把一个包含iterable里全部promise返回值的数组做为成功回调的返回值,顺序跟iterable的顺序保持一致;若是这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息做为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。(能够参考jQuery.when方法---译者注)promise

Promise.allSettled(iterable)
等到全部promises都已敲定(settled)(每一个promise都已兑现(fulfilled)或已拒绝(rejected))。
返回一个promise,该promise在全部promise完成后完成。并带有一个对象数组,每一个对象对应每一个promise的结果。

Promise.any(iterable)
接收一个Promise对象的集合,当其中的一个 promise 成功,就返回那个成功的promise的值。

Promise.race(iterable)
当iterable参数里的任意一个子promise被成功或失败后,父promise立刻也会用子promise的成功返回值或失败详情做为参数调用父promise绑定的相应句柄,并返回该promise对象。

Promise.reject(reason)
返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法

Promise.resolve(value)
返回一个状态由给定value决定的Promise对象。若是该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;不然的话(该value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,而且将该value传递给对应的then方法。一般而言,若是您不知道一个值是不是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value以Promise对象形式使用。

使用Promise

经过上面能够详细了解Promise的静态方法,后来就是使用Promise实例,

建立Promise

Promise 对象是由关键字 new 及其构造函数来建立的。该构造函数会把一个叫作“处理器函数”(executor function)的函数做为它的参数。这个“处理器函数”接受两个函数——resolve 和 reject ——做为其参数。当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败缘由(一般是一个错误对象)时,会调用reject 函数。

const myFirstPromise = new Promise((resolve, reject) => {
  // ?作一些异步操做,最终会调用下面二者之一:
  //
  //   resolve(someValue); // fulfilled
  // ?或
  //   reject("failure reason"); // rejected
});

想要某个函数拥有promise功能,只需让其返回一个promise便可。

function myAsyncFunction(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
  });
};

基础示例

let myFirstPromise = new Promise(function(resolve, reject){
    //当异步代码执行成功时,咱们才会调用resolve(...), 当异步代码失败时就会调用reject(...)
    //在本例中,咱们使用setTimeout(...)来模拟异步代码,实际编码时多是XHR请求或是HTML5的一些API方法.
    setTimeout(function(){
        resolve("成功!"); //代码正常执行!
    }, 250);
});

myFirstPromise.then(function(successMessage){
    //successMessage的值是上面调用resolve(...)方法传入的值.
    //successMessage参数不必定非要是字符串类型,这里只是举个例子
    console.log("Yay! " + successMessage);
});

Promise.all的基础使用

Promise.all() 方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,而且只返回一个Promise实例, 那个输入的全部promise的resolve回调的结果是一个数组。这个Promise的resolve回调执行是在全部输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会当即抛出错误,而且reject的是第一个抛出的错误信息。

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

输出:

> Array [3, 42, "foo"]

Promise平常使用

平常开发状况下咱们会常常跟Promise打交道,下面列举平常使用方式,

先定义一个Promise方法,

api.js

function getData(){
    
    return new Promise(resolve => {
        
        axios.get('xxxx').then(res => {
            
            resolve(res.data)
        })
    }
}

而后在组件里面调用分红两种方式接收:一、async await,二、then,看我的喜爱使用哪一种方式。

async await方式

async function query(){
    // res接收
    let res = await api.getData();
}

then方式

function query(){
    api.getData().then(res=>{
        // res接收
    });
}

Promise.all复杂使用

下面举个四级联动的例子介绍Promise.all的用法,能够跟Array.map方法结合使用,以下所示,数组中包含选中值:one,two,three和four,以及选中值对应的列表:oneList,twoList,threeList和fourList,而且四组数据之间存在关联关系。

let arry = [{
    one: '',
    oneList: [],
    two: '',
    twoList: [],
    three: '',
    threeList: [],
    four: '',
    fourList: []
},{
    one: '',
    oneList: [],
    two: '',
    twoList: [],
    three: '',
    threeList: [],
    four: '',
    fourList: []
},{
    one: '',
    oneList: [],
    two: '',
    twoList: [],
    three: '',
    threeList: [],
    four: '',
    fourList: []
}]
// 获取全部oneList数据
Promise.all(arr.map(item => this.getOneList()))
   .then(promiseData => {
       //按顺序输出id对应的oneList 数据
       arr.forEach((item,index) => {
           item.oneList = promiseData[index]
       })
   })
// 获取全部twoList数据
Promise.all(arr.map(item => this.getTwoList(item.one)))
   .then(promiseData => {
       //按顺序输出id对应的twoList 数据
       arr.forEach((item,index) => {
           item.twoList = promiseData[index]
       })
   })
// 获取全部threeList数据
Promise.all(arr.map(item => this.getThreeList(item.two)))
   .then(promiseData => {
       //按顺序输出id对应的threeList 数据
       arr.forEach((item,index) => {
           item.threeList = promiseData[index]
       })
   })
// 获取全部fourList数据
Promise.all(arr.map(item => this.getFourList(item.three)))
   .then(promiseData => {
       //按顺序输出id对应的fourList 数据
       arr.forEach((item,index) => {
           item.fourList = promiseData[index]
       })
   })

这样就能批量获取四级列表数据并赋值到arry数组上面,一开始个人解决思路并非这样,而是在forEach里面使用Promise,发现根本行不通,由于forEach自己就是异步的,因此还没等结果返回就已经执行了。

错误使用方式

arry.forEach((item, index) => {
    item.oneList = this.getOneList();
    item.twoList = this.getTwoList(item.one);
    item.threeList = this.getThreeList(item.one);
    item.fourList = this.getFourList(item.one);
})

虽然很简单,可是实际上行不通,必定要注意。

总结:

一、forEach不支持Promise

引用

JavaScript ES6 promise for loop duplicate
How to return many Promises and wait for them all before doing other stuff
Promise.all结合async/await
理解和使用Promise.all和Promise.race
JAVASCRIPT中FOREACH的异步问题