Promise从入门到精通

概念

Promise是ES6引入的进行异步编程的新的解决方案

备注:旧计划是单纯的应用回调函数

  • 从语法上来说:它就是一个构造函数,
  • 从性能上来说:能够封装异步的工作,并且能够对后果进行解决

Promise最大的益处:能够解决回调天堂的问题,并且它在指定回调和错误处理这一块更加的灵便与不便

回调天堂的典型情景:

异步编程有哪些?

答:fs文件操作、数据库操作、AJAX、定时器等等

为什么要应用Promise?

  1. 指定回调函数的形式更加灵便
    旧的形式:必须在启动异步工作前指定

    ·promise:启动异步工作 => 返回promise对象 => 给promise对象绑定回调函数(甚至能够在异步工作完结后指定多个回调)

  2. 反对链式调用,能够解决回调天堂问题

    回调天堂的毛病:1)不便于浏览;2)不便于异样解决

Promise的根本流程

promise的状态扭转

状态指的是promise实例中的一个属性:【PromiseState】

pending 未决定的

fulfilled 胜利

rejected 失败

1. pending => fulfilled

2. pending => rejected

promise对象的状态只有这两种扭转,1个promise对象的状态只能扭转一次,

不可能由fulfilled转rejected

也不可能由rejected转fulfilled

promise对象后果值属性介绍

实例对象中另一个属性:【PromiseResult】

保留的是胜利/失败的后果

resolve能够批改PromiseResult的值

rejected能够批改PromiseResult的值

如何应用Promise?

API

1.Promise构造函数:Promise(exector){}

1)exector函数:称为执行器函数 (resolve,reject)=>{}

2)resolve函数:是Promise外部定义的,胜利时咱们调用resolve函数

3)reject函数:是Promise外部定义的,失败时咱们调用reject函数

阐明:exector会在Promise外部立刻同步调用,异步操作在执行器中执行

2.Promise.prototype.then办法:(onResolved,onRejected)=>{}

1)onResolved函数:指定胜利的回调函数 value=>{}

2)onRejected函数:指定失败的回调函数 reason=>{}

阐明:指定用于失去胜利value的胜利回调和用于失去失败reason的失败回调,返回一个新的promise对象

3.Promise.prototype.catch办法:(onRejected)=>{}

onRejected函数:指定失败的回调函数 reason=>{}

阐明:then()的语法糖,相当于then(undefined,onRejected)

4.Promise.resolve办法 (value)=>{}

1)value:胜利的数据或promise对象

阐明:返回一个胜利/失败的promise对象

作用:为了疾速失去一个promise对象,而且可能封装1个值,将这个值转化为promise对象

如果传入的参数为非promise类型的对象,则返回的后果为胜利的promise对象

如果传入的参数为promise对象,则参数的后果决定了resolve的后果

5.Promise.reject办法:(reason)=>{}

作用:疾速返回一个失败的promise对象

返回的后果永远都是失败的promise对象

6.Promise.all办法:(promises数组)=>{}

参数:蕴含n个promise的数组

阐明:返回一个新的promise对象,只有所有的promise都胜利才胜利,只有有一个失败就间接失败

7.Promise.race办法:(promises数组)=>{}

race有赛跑的意思

参数:蕴含n个promise的数组

阐明:返回一个新的promise对象,第一个扭转状态的promise就是最终的后果状态

promise的几个关键问题

1. 如何扭转promise的状态?

(1) resolve(value): 如果以后是pending就会变为fulfilled

(2) reject(reason): 如果以后是pending就会变为rejected

(3) 抛出异样: 如果以后是pending就会变为rejected

2. 一个promise指定多个胜利/失败回调函数, 都会调用吗?

当promise扭转为对应状态时都会调用

3. 扭转promise状态和指定回调函数谁先谁后?

(1) 都有可能, 失常状况下是先指定回调再扭转状态, 但也能够先改状态再指定回调

(2) 如何先改状态再指定回调?

① 在执行器中间接调用resolve()/reject()

② 提早更长时间才调用then()

(3) 什么时候能力失去数据?

① 如果先指定的回调, 那当状态产生扭转时, 回调函数就会调用, 失去数据

② 如果先扭转的状态, 那当指定回调时, 回调函数就会调用, 失去数据

4. promise.then()返回的新promise的后果状态由什么决定?

(1) 简略表白: 由then()指定的回调函数执行的后果决定

(2) 具体表白:

① 如果抛出异样, 新promise变为rejected, reason为抛出的异样

② 如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值

③ 如果返回的是另一个新promise, 此promise的后果就会成为新promise的后果

5. promise如何串连多个操作工作?

(1) promise的then()返回一个新的promise, 能够开成then()的链式调用

(2) 通过then的链式调用串连多个同步/异步工作

let p = new Promise((resolve,reject)=>{  setTimeout(()=>{    resolve('ok');  },1000);});p.then(v=>{  return new Promise((resolve,reject)=>{    resolve('success');  });}).then(v=>{  console.log(v);}).then(v=>{  console.log(v);})

6. promise异样传透?

(1) 当应用promise的then链式调用时, 能够在最初指定失败的回调,

(2) 后面任何操作出了异样, 都会传到最初失败的回调中解决

let p = new Promise((resolve,reject)=>{  reject('err');});p.then(v=>{  console.log(111);}).then(v=>{  console.log(222);}).then(v=>{  console.log(333);}).catch(r=>{  console.log(r);});

7. 中断promise链?

(1) 当应用promise的then链式调用时, 在两头中断, 不再调用前面的回调函数

(2) 方法: 在回调函数中返回一个pendding状态的promise对象

代码展现

//申明函数        执行器   『同步回调』function Promise(executor) {    //设置实例对象的属性    this.PromiseState = 'pending';    this.PromiseResult = undefined;    this.callbacks = [];    //申明函数    const success = (value) => {        if (this.PromiseState !== 'pending') return;        //批改状态为胜利  PromiseState        this.PromiseState = 'fulfilled';        //设置胜利的后果值 PromiseResult        this.PromiseResult = value;        //调用回调        if (this.callbacks.length > 0) {            this.callbacks.forEach(cbObj => {                //执行胜利的回调                cbObj.ok();            })        }    }    const fail = (reason) => {        if (this.PromiseState !== 'pending') return;        //批改状态为失败  PromiseState        this.PromiseState = 'rejected';        //设置胜利的后果值 PromiseResult        this.PromiseResult = reason;        //调用回调        if (this.callbacks.length > 0) {            this.callbacks.forEach(cbObj => {                //执行胜利的回调                cbObj.ng();            })        }    }    try {        //调用执行器函数        executor(success, fail);    } catch (e) {        //调用 fail 函数        fail(e);    }}Promise.prototype.then = function (onFulfilled, onRejected) {    //判断  异样穿透    if(typeof onRejected !== 'function'){        onRejected = reason => {throw reason};    }    //值传递    if(typeof onFulfilled !== 'function'){        onFulfilled = value => value;    }    return new Promise((resolve, reject) => {        //封装函数简化代码        let callback = (type) => {            try {                let res = type(this.PromiseResult);                //判断                if (res instanceof Promise) {                    res.then(v => {                        resolve(v);                    }, r => {                        reject(r);                    })                } else {                    resolve(res);                }            } catch (e) {                reject(e);            }        }        //判断 胜利        if (this.PromiseState === 'fulfilled') {            setTimeout(() => {                callback(onFulfilled);//             })        }        //失败        if (this.PromiseState === 'rejected') {            setTimeout(() => {                callback(onRejected);            })        }        //pending         if (this.PromiseState === 'pending') {            //保留回调            this.callbacks.push({                ok: function () {                    //胜利                    callback(onFulfilled);                },                ng: function () {                    callback(onRejected);                }            })        }    });}Promise.prototype.catch = function(onRejected){    return this.then(undefined, onRejected);}Promise.resolve = function(value){    return new Promise((resolve,reject) => {        //判断        if(value instanceof Promise){            //value.then(resolve, reject); 这行代码和上面5行代码性能一样            value.then(v=>{                resolve(v);            }, r => {                reject(r);            });        }else{            resolve(value);        }    })}Promise.reject = function(reason){    return new Promise((resolve, reject) => {        reject(reason);    })}Promise.all = function (promiseArr) {    return new Promise((resolve, reject) => {        let count = 0;        let arr = [];        for (let i = 0; i < promiseArr.length; i++) {            promiseArr[i].then(v => {                count++;                arr[i] = v;                if (count === promiseArr.length) {                    resolve(arr);                }            }, r => {                reject(r);            });        }    });}Promise.race = function (promiseArr) {    return new Promise((resolve, reject) => {        promiseArr.forEach(item => {            item.then(v => {                resolve(v);            }, r => {                reject(r);            });        });    });}

面试题1:

let p = new Promise((resolve, reject) => {    reject("error");});p.then(v => {    console.log(v);}).then(v => {    console.log(v);}, r => {    console.log(r); // error}).then(v => {    console.log(v);  // undefined}, r => {    console.warn(r); });