前言

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

Promise详解

通过MDN 官网文档对Promise有段介绍:Promise 对象用于示意一个异步操作的最终实现 (或失败)及其后果值。

一个 Promise 对象代表一个在这个 promise 被创立进去时不肯定已知的值。它让您可能把异步操作最终的胜利返回值或者失败起因和相应的处理程序关联起来。 这样使得异步办法能够像同步办法那样返回值:异步办法并不会立刻返回最终的值,而是会返回一个 promise,以便在将来某个时候把值交给使用者。

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

  • 待定(pending): 初始状态,既没有被兑现,也没有被回绝。
  • 已兑现(fulfilled): 意味着操作胜利实现。
  • 已回绝(rejected): 意味着操作失败。

待定状态的 Promise 对象要么会通过一个值被兑现(fulfilled),要么会通过一个起因(谬误)被回绝(rejected)。当这些状况之一产生时,咱们用 promise 的 then 办法排列起来的相干处理程序就会被调用。如果 promise 在一个相应的处理程序被绑定时就曾经被兑现或被回绝了,那么这个处理程序就会被调用,因而在实现异步操作和绑定解决办法之间不会存在竞争状态。

因为 Promise.prototype.then 和 Promise.prototype.catch 办法返回的是 promise, 所以它们能够被链式调用。


1、构造函数

Promise()
创立一个新的 Promise 对象。该构造函数次要用于包装还没有增加 promise 反对的函数。

2、静态方法

Promise.all(iterable)
这个办法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都胜利的时候才会触发胜利,一旦有任何一个iterable外面的promise对象失败则立刻触发该promise对象的失败。这个新的promise对象在触发胜利状态当前,会把一个蕴含iterable里所有promise返回值的数组作为胜利回调的返回值,程序跟iterable的程序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all办法常被用于解决多个promise对象的状态汇合。(能够参考jQuery.when办法---译者注)

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)        })    }}

而后在组件外面调用分成两种形式接管:1、async await,2、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);})

尽管很简略,然而实际上行不通,肯定要留神。

总结:

1、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的异步问题