深入了解ES6–11.Promise和异步编程

作者 : 开心源码 本文共7475个字,预计阅读时间需要19分钟 发布时间: 2022-05-11 共178人阅读

主要知识点:Promise生命周期、Promise基本操作、Promise链、响应多个Promise以及集成Promise

Promise与异步编程.png

1. Promise基础

什么是回调地狱?

当用回调函数来进行事件解决的时候,假如嵌套多层回调函数的时候,就会出现回调地狱,例如:

method1(function(err, result) {    if (err) {        throw err;    }     method2(function(err, result) {        if (err) {            throw err;        }         method3(function(err, result) {            if (err) {                throw err;            }             method4(function(err, result) {                if (err) {                    throw err;                }                 method5(result);            });        });    });});

像本例一样嵌套多个方法调使用会创立错综复杂的代码,会难以了解与调试。当想要实现更复
杂的功可以时,回调函数也会存在问题。要是你想让两个异步操作并行运行,并且在它们都结
束后提示你,那该怎样做?要是你想同时启动两个异步操作,但只采使用首个结束的结果,那
又该怎样做?而用Promise就可以避免回调地狱的情况。

Promise能当做是一个占位符,表示异步操作的执行结果。函数能返回一个Promise,而不必订阅一个事件或者者向函数传递一个回调函数。

Promise的生命周期

每个 Promise 都会经历一个短暂的生命周期,初始为挂起状态(pending state) ,这表示异步操作尚未结束。一个挂起的 Promise 也被认为是未决的(unsettled )。一旦异步操作结束, Promise就会被认为是已决的(settled ) ,并进入两种可可以状态之一:

  1. 已完成(fulfilled ) : Promise 的异步操作已成功结束;

  2. 已拒绝(rejected ) : Promise 的异步操作未成功结束,可可以是一个错误,或者由其余起因导致。

内部的[[PromiseState]] 属性会被设置为"pending""fulfilled" 或者 "rejected",以反映Promise的状态。该属性并未在 Promise 对象上被暴露出来,因而你无法以编程方式判断 Promise 究竟处于哪种状态。不过你能用then()方法在 Promise 的状态改变时执行少量特定操作。

  1. then()方法

    then()方法在所有的 Promise 上都存在,并且接受两个参数。第一个参数是 Promise 被完成时要调使用的函数,异步操作的结果数据都会被传入这个完成函数。第二个参数则是 Promise 被拒绝时要调使用的函数,与完成函数类似,拒绝函数会被传入与拒绝相关联的任何附加数据。then()方法的两个参数是可选的,因而能自由组合监听完成和失败的解决函数;

  2. catch()方法

    Promise有catch()方法,等同于只传递拒绝解决函数给then()方法:

     promise.catch(function(err) {     // 拒绝     console.error(err.message); }); // 等同于: promise.then(null, function(err) {     // 拒绝     console.error(err.message); });

创立未决的Promise

用Promise构造器能创立一个Promise实例,此构造器接收一个参数:一个被称之为执行器(excutor)的函数,该函数包含了resolve()函数和reject()函数这两个参数。resolve()函数在异步任务执行成功时调使用,而reject()函数在异步任务执行失败时调使用。例如:

let promise = new Promise(function(resolve,reject){    console.log('hi, promise');    resolve();});promise.then(()=>{    console.log('hi, then');});console.log('hi');输出:hi, promisehihi then

从输出结果能看出,Promise构造器中的代码是最先执行的,而then()代码是最后执行的,这是由于只有在Promise中的解决器函数执行结束之后,then()方法中的完成解决函数或者者拒绝解决函数才会增加到作业队列的尾部。

创立已决的Promise

  1. Promise.resolve()

Promise.resolve()方法接收一个参数,并会返回一个处于已完成状态的 Promise ,在then()方法中用完成解决函数才可以提取该完成态的Promise传递的值,例如:

let promise = Promise.resolve('hi');promise.then((value)=>{    console.log(value); //hi});
  1. 用Promise.reject()

能用Promise.reject()方法来创立一个已拒绝状态的Promise,同样只有在拒绝解决函数中或者者catch()方法中才可以接受reject()方法传递的值:

let reject = Promise.reject('reject');reject.catch((value)=>{    console.log(value); //reject})

非Promise的thenable

当一个对象拥有一个可以接受resolvereject参数的then()方法时,该对象就会被认为是一个非Promisethenable,例如:

let thenable = {    then:function(resolve,reject){        resolve('hi');    }}

Promise.resolve()Promise.reject()方法都可以够接受非Promise的thenable作为参数,当传入了非Promise的thenable时,这些方法会创立一个新的Promise,并且能用then()方法对不同状态进行操作:

创立一个已完成的Promise

let thenable = {    then:function(resolve,reject){        resolve('hi');    }}let promise = Promise.resolve(thenable);promise.then((value)=>{    console.log(value); //hi});

同样利使用thenable能创立一个已拒绝的Promise:

let thenable = {    then:function(resolve,reject){        reject('hi');    }}let promise = Promise.resolve(thenable);promise.then(null,(value)=>{    console.log(value);});

执行器错误

当执行器内部抛出错误,那么Promise的拒绝解决函数就会被调使用,例如:

let promise = new Promise(function(resolve,reject){    throw new Error('Error!');})promise.catch(function(msg){    console.log(msg); //error})

2. Promise链

除了用单个Promise外,多个Promise能进行级联用,实际上then()方法或者者catch()方法会返回一个新的Promise,仅当前一个Promise被决议之后,后一个Promise才会进行解决。

串联Promise

let p1 = new Promise(function(resolve,reject){    resolve('hi');});p1.then((value)=>{    console.log(value);    throw new Error('Error!');}).catch(function(error){    console.log(error);})

能看出当p1的then()方法执行结束后会返回一个Promise,因而,在此基础上能继续执行catch()方法。同时,Promise链允许捕获前一个Promise的错误

Promise链中传递值

Promise链的另一个重要方面是可以从一个Promise传递数据给另一个Promise的可以力。前一个Promise的完成解决函数的返回值,传递到下一个Promise中。

//Promise链传递值let p1 = new Promise(function(resolve,reject){    resolve(1);})p1.then(value=>value+1).then(value=>{    console.log(value);})

p1的完成解决函数返回了value+1,也就是2,会传入到下一个Promise的完成解决函数,因而,第二个then()方法中的完成解决函数就会输出2。拒绝解决函数同样能被使用于在Promise链中传递数据。

Promise链中传递Promise

在完成或者者拒绝解决函数中能返回基本类型值,从而能在Promise链中传递。另外,在Promise链中也能传递对象,假如传递的是Promise对象,就需要额外的解决:

传递已完成状态的Promise

let p1 = new Promise(function(resolve,reject){    resolve(1);});let p2 = new Promise(function(resolve,reject){    resolve(2);})p1.then(value=>{    console.log(value);    return p2;}).then(value=>{    console.log(value);});输出:1  2

p1中返回了Promise对象p2,当p2完成时,才会调使用第二个then()方法,将值value传到完成解决函数中。若Promise对象p2被拒绝后,第二个then()方法中的完成解决函数就不会执行,只可以通过拒绝解决函数才可以接收到p2传递的值:

let p1 = new Promise(function(resolve,reject){    resolve(1);});let p2 = new Promise(function(resolve,reject){    reject(2);})p1.then(value=>{    console.log(value);    return p2;}).catch(value=>{    console.log(value);});

3. 响应多个Promise

假如想监视多个Promise的状态,从而决定下一步动作,能用ES6提供的两个方法:Promise.all()Promise.race()

Promise.all()

Promise.all()方法可以接受单个可迭代对象(如数组)作为参数,可迭代对象的元素都是Promise。该方法会返回一个Promise,只有传入所有的Promise都已完成,所返回的Promise才会完成,例如:

//Promise.all()let p1 = new Promise(function(resolve,reject){    resolve(1);})let p2 = new Promise(function(resolve,reject){    resolve(2);})let p3 = new Promise(function(resolve,reject){    resolve(3);})let p4 = Promise.all([p1,p2,p3]);p4.then(value=>{    console.log(Array.isArray(value)); //true    console.log(value); //[1,2,3]})

Promise.all() 的调使用创立了新的Promise p4,在 p1p2p3 都被完成后, p4 最终会也被完成。传递给 p4 的完成解决函数的结果是一个包含每个决议值(1 、 2 与 3 ) 的数组,这些值的存储顺序保持了待决议的 Promise 的顺序(与完成的先后顺序无关) ,因而你能将结果匹配到每个Promise

若传递给Promise.all() 的某个 Promise 被拒绝了,那么方法所返回的 Promise 就会立刻被拒绝,而不必等待其余的 Promise 结束

//Promise.all()let p1 = new Promise(function(resolve,reject){    resolve(1);})let p2 = new Promise(function(resolve,reject){    reject(2);})let p3 = new Promise(function(resolve,reject){    resolve(3);})let p4 = Promise.all([p1,p2,p3]);p4.catch(value=>{    console.log(Array.isArray(value)); //true    console.log(value); //2})

在此例中, p2 被用数值 2 进行了拒绝,则 p4 的拒绝解决函数就立刻被调使用,而不会
等待 p1 或者 p3 结束执行(它们依然会各自结束执行,只是 p4 不等它们) 。

拒绝解决函数总会接受到单个值,而不是一个数组。该值是被拒绝的Promise所返回的拒绝值。

Promise.race()

Promise.race()方法接收一个元素是Promise的可迭代对象,并返回一个新的Promise。一旦传入Promise.race()的可迭代对象中有一个Promise是已决状态,那么返回的Promise对象就会立刻成为已决状态。

Promise.all()方法得必需等到所有传入的Promise一律变为已决状态,所返回的Promise才会已决。

let p1 = new Promise(function(resolve,reject){    resolve(1);})let p2 = new Promise(function(resolve,reject){    resolve(2);})let p3 = new Promise(function(resolve,reject){    resolve(3);})let p4 = Promise.race([p1,p2,p3]);p4.then(value=>{    console.log(Array.isArray(value)); //false    console.log(value); //1})

Promise.race() 方法传入的Promise中哪一个Promise先变成已完成状态,就会将值传递给所返回的Promise对象的完成解决函数中。若哪一个Promise最先变成已拒绝状态,同样的,会将值传递给p4的拒绝解决函数中。

4. 继承Promise

能继承Promise实现自己设置的Promise,例如:

class MyPromise extends Promise {    // 用默认构造器    success(resolve, reject) {        return this.then(resolve, reject);    }     failure(reject) {        return this.catch(reject);    }} let promise = new MyPromise(function(resolve, reject) {    resolve(42);});promise.success(function(value) {    console.log(value); // 42}).failure(function(value) {    console.log(value);});

在此例中, MyPromise 从 Promise 上派生出来,并拥有两个附加方法。 success() 方法模拟了 resolve()failure() 方法则模拟了 reject()

5. 总结

  1. Promise 具备三种状态:挂起、已完成、已拒绝。一个 Promise 起始于挂起态,并在成功时转为完成态,或者在失败时转为拒绝态。 then() 方法允许你绑定完成解决函数与拒绝解决函数,而 catch() 方法则只允许你绑定拒绝解决函数;

  2. 可以够将多个Promise串联起来组成Promise链,并且可以够在中间传递值,甚至是传递Promise对象。 then() 的调使用都创立并返回了一个新的 Promise ,只有在前一个 Promise 被决议过,新 Promise 也会被决议。 同时也能用Promise.all()和Promise.race()方法来管理多个Promise。

             

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 深入了解ES6–11.Promise和异步编程

发表回复