Depth understanding of promise

1. Promise foundation

What is a callback hell?

When using a callback function to handle the event, when the multi-layer if nested callback function, there will be a callback hell, for example:

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

As in this example as multiple nested method call creates intricate code that will be difficult to understand and debug. When you want to achieve more complex
when complicated functions, the callback function will be a problem. If you want to run two asynchronous operations in parallel, and they all bear
to remind you that after the beam, then how to do? If you want to simultaneously launch two asynchronous operation, but only using the results of the first end, then
how should we do? Promise will be able to avoid the use of callback hell circumstances.

Promise can be used as a placeholder to indicate asynchronous operation of the execution result. Function returns a Promise, without having to subscribe to an event or pass a callback function to function.

Promise life cycle

Each Promise will experience a short life cycle, initially suspended state (pending state), which represents the asynchronous operation is not over yet. A pending Promise is also considered pending (unsettled). Once the asynchronous operation is completed, Promise will be considered one of the possible states has already decided (settled), and into two types:

  1. Completed (Fulfilled) : Promise of asynchronous operation has been completed successfully;
  2. Rejected (Rejected) : Promise asynchronous operation is not successfully concluded, could be a mistake, or caused by other reasons.

Inside the [[PromiseState]]property is set "pending", "fulfilled"or "Rejected" ,以反映Promise 的状态。该属性并未在 Promise 对象上被暴露出来,so you can not determine programmatically Promisein the end what state. But you can use then()to perform certain operations when the change in state Promise method.

  1. then () method

    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, promise hi hi 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。

 

 

 

 




                                                                                                                         

 

 

 

                                                                                              飞机票:https://www.jianshu.com/p/df667b84b121

Guess you like

Origin www.cnblogs.com/yebai/p/11236383.html