promise链式调用和promise内嵌套promise的学习

参考链接:

Promise.then链式调用顺序 (这一篇详细讲解then中嵌套promise和各种情况说明,必看,研究)

《ES6标准入门》(阮一峰)--16.Promise 对象 (这一篇讲解promise比较全,有promise的各种方法讲解)

Promise基本使用及方法介绍 (promise讲解比较全,辅助参考)

Promise中then的执行顺序详解 (有简化版then实现,参考)

面试官:“你能手写一个 Promise 吗” (手写then,研究,未看)

题目七:并发加载三个图片 

Promise的含义:

Promise 是一个对象,从它可以获取异步操作的消息。Promise 是目前前端解决异步问题的统一方案

Promise对象有以下两个特点:

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。

只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从进行中变为已成功和从进行中变为已失败。

只要这两种情况发生,状态就不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。

promise优点:

promise对象,可以将 异步操作 以 同步操作的流程 表达出来,避免层层嵌套

Promise缺点:

首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。

其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

第三,当处于进行中状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

promise的基本用法:

promise内部是同步的,但是then方法是异步的

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

resolve 函数的作用是,将Promise 对象的状态从“未完成”变为“成功”(即从 pending 变为 fulfilled),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject 函数的作用是,将Promise 对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise实例生成以后,可以用then方法分别指定fulfilled状态和rejected状态的回调函数。

Promise.then(function(value) {

    // success

}, function(error) {

    // failure

})

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise 对象的状态变为resolved时调用,第二个回调函数是Promise 对象的状态变为rejected时调用。

其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise 对象传出的值作为参数。

下面是一个用Promise对象实现的 Ajax 操作的例子。

const getJSON = function(url) {

  const promise = new Promise(function(resolve, reject){

    const handler = function() {

      if (this.readyState !== 4) {

        return;

      }

      if (this.status === 200) {

        resolve(this.response);

      } else {

        reject(new Error(this.statusText));

      }

    };

    const client = new XMLHttpRequest();

    client.open("GET", url);

    client.onreadystatechange = handler;

    client.responseType = "json";

    client.setRequestHeader("Accept", "application/json");

    client.send();

  });

  return promise;

};

getJSON("/posts.json").then(function(json) {

  console.log('Contents: ' + json);

}, function(error) {

  console.error('出错了', error);

});

resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例

const p1 = new Promise(function (resolve, reject) {

  // ...

});

const p2 = new Promise(function (resolve, reject) {

  // ...

  resolve(p1);

})

上面代码中,p1和p2都是 Promise 的实例,但是p2的resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。

注意,这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;

如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。

Promise.prototype.then():

总结三点:

(1) 当前一个then中的代码都是同步执行的,执行结束后第二个then即可注册进入微任务队列。

(2) 当前一个then中有return 关键字,需要return的内容完全执行结束,第二个then才会注册进入微任务队列。

(3)then 方法接受的参数是函数,而如果传递的并非是一个函数,它实际上会将其解释为 then(null),这就会导致前一个 Promise 的结果会穿透下面。

Promise.resolve(1)

  .then(2)

  .then(Promise.resolve(3))

  .then(console.log)

// 1

Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。

前面说过,then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。

then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。

const getJSON = ()=>(new Promise((resolve,reject)=>resolve(1)))

getJSON().then(function(json) {

console.log(json)

return json;

}).then(function(post) {

console.log(post)

});

上面的代码使用then方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。

采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),

这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。

const getJSON = (num)=>(new Promise((resolve,reject)=>resolve(num)))

getJSON(1).then(function(post) {

return getJSON(2);

}).then(function (comments) {

console.log("resolved: ", comments);

}, function (err){

console.log("rejected: ", err);

});

// 打印:resolved:  2

上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。

如果变为resolved,就调用第一个回调函数,如果状态变为rejected,就调用第二个回调函数。

Promise.resolve():

promise.resolve()可以将对象转换为promise对象

Promise.resolve('foo')

// 等价于

new Promise(resolve => resolve('foo'))

Promise.resolve方法的参数分成四种情况。

(1)参数是一个 Promise 实例

如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。

(2)参数是一个thenable对象

thenable对象指的是具有then方法的对象,比如下面这个对象。

let thenable = {

  then: function(resolve, reject) {

    resolve(42);

  }

};

Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。

let thenable = {

  then: function(resolve, reject) {

    resolve(42);

  }

};

let p1 = Promise.resolve(thenable);

p1.then(function(value) {

  console.log(value);  // 42

});

上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42。

(3)参数不是具有then方法的对象,或根本就不是对象

如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。

const p = Promise.resolve('Hello');

p.then(function (s){

  console.log(s)

});

// Hello

上面代码生成一个新的 Promise 对象的实例p。由于字符串Hello不属于异步操作(判断方法是字符串对象不具有 then 方法),返回 Promise 实例的状态从一生成就是resolved,所以回调函数会立即执行。Promise.resolve方法的参数,会同时传给回调函数。

Promise.prototype.catch():

Promise.prototype.catch() 是 .then(null, rejection) 的别名,用于指定发生错误时的回调函数

如果promise实例对象的状态变为rejected,

就会触发 catch() 方法指定的回调函数

如果 .then() 方法指定的回调函数在运行中抛出错误,也会被 catch() 方法捕获

promise对象的错误具有冒泡性质,

会一直向后传递,直到被捕获为止

( 也就是说错误总是会被下一个catch语句捕获 )

一般来说,不要在.then()方法中定义rejected状态的回调函数,

而总是使用 .catch()方法

一般总是建议,promise对象后要跟 catch()方法,这样可以处理 promise内部发生法的错误,catch() 方法返回的还是promise对象,

因此后面还可以接着调用 then() 方法

catch() 方法中还能再抛错误,如果 catch()方法抛出错误后,后面没有catch()方法,错误就不会被捕获,也不会传递到外层。

如果catch()方法抛出错误后,后面有then()方法,会照常执行,后面有catch()方法,错误还会被再一次捕获

async和await:

Async返回的是Promise对象

async/await其实就是promise和generator的语法糖:

async function demo01() {

console.log(1)

return ‘demo1’;

}

demo01().then(function(a){

console.log(a)

});

输出结果为1,demo1

async用来表示函数是异步的,定义的函数会返回一个promise对象,可以使用then方法添加回调函数。上列代码中的async函数中的console.log(1)可以当一个同步的队列执行,也就是说但你在定义async function的时候 里面的代码是以同步的方式执行,只不过async的返回是一个promise,可以用.then()的方式去执行回调,如同上述内容。若 async 定义的函数有返回值,return ‘demo1’;相当于Promise.resolve('demo1’),没有声明式的 return则相当于执行了Promise.resolve();

await是和async一起来使用,一般为:

async function demo2(){

console.log(7)

await a()

console.log(6)

}

demo2()

function a() {

console.log(‘demo2’)

}

当他和promise一起用的话:

async myFun( ){ await new Promise(resolve=>{ }) }


总结:

一般async与await同步出现

async返回promise对象

await出现在async函数内部,单独只用会报错

componentDidMount() {

        const funSync1 = () => console.log('我是同步函数1111111')

        const funSync2 = () => console.log('我是同步函数2222222')

        const funAsync = async () => {    // async关键字,定义的函数是异步函数,返回promise对象

            await funSync1()

        }

        funAsync().then(funSync2())

        console.log('bbbb')

}

// 先把两个同步函数变成了异步,在异步函数中,先执行funSync1,后执行funSync2

// 使用async关键字后,会把同步包装成的异步函数,按同步方式执行

// 所以最后得到的输出顺序是:

// 我是同步函数1111111

// 我是同步函数2222222

// bbbb



异步和同步:

同步直接拿到结果

异步不能直接拿到结果

回调不一定用在异步,也可以用在同步

异步不一定要用到回调,也可以用轮询。

异步任务不能拿到结果

异步任务完成时调用回调

结果作为参数



下面是一些例子,也有面试题,主要用来辅助弄懂js执行的顺序和promise.then执行顺序:

例子1:

const p1 = () => (new Promise((resolve, reject) => {

                console.log(1);

                let p2 = new Promise((resolve, reject) => {

                    console.log(2);

                    const timeOut1 = setTimeout(() => {

                        console.log(3);

                        resolve(4); // 不执行代码,因为p2的promise对象已经有结果

                    }, 0)

                    resolve(5);

                });

                resolve(6);

                p2.then((arg) => {

                    console.log(arg);

                });

            }));

            const timeOut2 = setTimeout(() => {

                console.log(8);

                const p3 = new Promise(reject => {

                    reject(9);

                }).then(res => {

                    console.log(res)

                })

            }, 0)

            p1().then((arg) => {

                console.log(arg);

            });

            console.log(10);

            // 打印结果:1,2,10,5,6,8,9,3

            第一轮

            宏任务:timeOut2,timeOut1

            微任务:p2.then,p1.then(本轮结束前清空)

            打印:1,2,10,5,6

            第二轮

            宏任务:timeOut2,timeOut1

            微任务:p3.then(本轮结束前清空)

            打印:8,9

            第三轮

            宏任务:timeOut1

            微任务:

            打印:3

例子2:

console.log('script start');

            // Promise.resolve('foo') 等价于 new Promise(resolve => resolve('foo')),所以会先让同步任务先执行,所以这里打印script start,然后是script end。

            setTimeout(function () {

                console.log('setTimeout---0');

            }, 0);

            setTimeout(function () {

                console.log('setTimeout---200');

                setTimeout(function () {

                    console.log('inner-setTimeout---0');

                });

                Promise.resolve().then(function () {

                    console.log('promise5');

                });

            }, 200);

            Promise.resolve().then(function () {

                console.log('promise1');

                // 每个new promise内有resolve会先优先于.then执行,所以这里会先打印promise1,然后打印promise3,再打印promise2(个人理解,源码类似这个逻辑)

            }).then(function () {

                console.log('promise2');

            });

            Promise.resolve().then(function () {

                console.log('promise3');

            });

            console.log('script end');

            // 执行结果: script start,script end,promise1,promise3,promise2,setTimeout---0,setTimeout---200,promise5,inner-setTimeout---0

例子3:

const promise = new Promise((resolve, reject) => {

                console.log(1)

                    setTimeout(() => {

                        console.log('once')

                        resolve('success')

                    }, 1000)

            })

            // 1打印后,promise.then刚开始没有执行,因为promise对象还没有结果,也就是状态还是pendding,等到执行setTimeout后有了状态后才执行promise.then

            // 另外因为状态改变后不会再改变,所以两个promise.then打印都是一样结果

            promise.then((res) => {

                console.log(res)

                })

            promise.then((res) => {

                console.log(res)

            })

            // 执行结果:1,once,success,success

例子4:

let thenable = {

                then: function(resolve, reject) {

                    resolve(6);

                }

            };

            // let p = Promise.resolve();

            let p = new Promise((resolve, reject) =>{

                resolve(7)

            });

            setTimeout(()=>{

                console.log(1)

            },0)

            // Promise.resolve()方法返回一个新的 Promise 对象,状态为resolved。Promise.resolve().then就是微任务,所有比setTimeout提前打印

            // promise.resolve()方法:参数不是具有then方法的对象,或根本就不是对象(也就是2,5,4)和参数是一个promise对象(也就是7),他们的优先级高于参数是一个thenable对象


            Promise.resolve().then(()=>{

                console.log(2)

            })

            Promise.resolve(thenable).then((value)=>{

                console.log(value)

            })

            Promise.resolve(p).then((v)=>{

                console.log(v)

            })

            Promise.resolve('5').then(()=>{

                console.log('5')

            })

            Promise.resolve().then(()=>{

                console.log(4)

            })

            console.log(3)

            //执行结果: 3,2,7,5,4,6,1

例子5:

const first = () => (new Promise((resolve, reject) => {

                console.log(3)

                let p = new Promise((resolve, reject) => {

                    console.log(7)

                    setTimeout(() => {

                        console.log(5)

                        resolve(6)

                    }, 0)

                    resolve(1)

                })

                resolve(2)

                p.then((arg) => {

                    console.log(arg)

                })

            }))

            console.log(4)

            // 这道题没什么特殊,主要指出要注意new Promise有没有被放在函数里,如果放在函数里,是要等到被调用(first())才会执行,而不是new promise就直接执行了

            first().then((arg) => {

                console.log(arg)

            })


            // 执行结果: 4,3,7,1,2,5

            // 第一轮

            // 宏任务:setTimeout

            // 微任务:p.then,first.then

            // 打印:4,3,7,1,2

            // 第二轮

            // 宏任务:setTimeout

            // 微任务:

            // 打印:5

例子6:

setTimeout(() => {

                console.log("0")

            }, 0)

            new Promise((resolve,reject)=>{ // promise1

                console.log("1")

                resolve() // 第一个resolve

            }).then(()=>{       

                console.log("2")

                new Promise((resolve,reject)=>{ // promise2

                    console.log("3")

                    resolve() // 第二个resolve

                }).then(()=>{     

                    console.log("4")

                }).then(()=>{     

                    console.log("5")

                })

            }).then(()=>{ 

                console.log("6")

            })


            new Promise((resolve,reject)=>{ // promise3

                console.log("7")

                resolve() // 第三个resolve

            }).then(()=>{       

                console.log("8")

            })

            // 首先执行两个new Promise打印1,7,然后是resolve1和resolve3进入队列。执行resolve1,打印2,3,resolve2进入队列(这个时候对于promise1的第一个then来说,已经有了fullfilled状态,所以promie1第二个then也进入队列),

            // 所以打印8,4, 6,5,最后打印0

            // 执行结果:1,7,2,3,8,4,  6,5,(这一步要注意,promise1.then是先进入任务队列,不是5,6),0

例子7:

async function async1() {

            console.log('async1 start')

            await async2()  // 相当于async2().then(() => {}),所以下面这个'async1 end'是先被放到微任务队列

            console.log('async1 end')

        }

        async function async2() {

            console.log('async2')

        }

        console.log('script start')

        setTimeout(() => {

            console.log('setTimeout')

        }, 0)

        async1()


        new Promise(function (resolve) {

            console.log('promise1')

            resolve()

        }).then(function () {

            console.log('promise2')

        })

        console.log('script end')

        // 这里比较容易弄错的是async2,async1 end的位置。async1 start之后为什么会马上执行async2,应该是这个await的作用(变异步为同步,必须等待await后的函数先执行)

        // 然后就是await async2()相当于async2().then(() => {}),所以下面这个'async1 end'是先被放到微任务队列,Promise.then后面放入微任务队列,所以async1 end比promise2先执行。


        // 答案依次:script start ==> async1 start ==> async2 ==> promise1 ==>

        // script end ==> async1 end ==> promise2 ==> setTimeOut

例子8:

// async用来表示函数是异步的,定义的函数会返回一个promise对象,可以使用then方法添加回调函数。

        // 也就是说你在定义async function的时候 里面的代码是以同步的方式执行,只不过async的返回是一个promise,可以用.then()的方式去执行回。

        // 若 async 定义的函数有返回值,return ‘demo1’;相当于Promise.resolve('demo1’),没有声明式的 return则相当于执行了Promise.resolve();

        async function demo01() {

            console.log(1)

            return 'demo1';

        }

        console.log('0')

        demo01().then(function(a){

            console.log(a)

        });

        console.log('8')

        async function demo2(){

            console.log(7)

            await a()

            console.log(6)

        }

        demo2()

        let promise = new Promise(function(resolve, reject){

            resolve(5)

            console.log(3)

            setTimeout(function(){console.log(4)})

        })

        console.log(2)

        promise.then(function(a){

            console.log(a)

        })

        function a(){

            console.log('demo2')

        }

        // 0,1,8,7,demo2,3,2,demo1,6,5,4

例子9:有点难

const p1 = Promise.resolve();

            let p3;

            const p2 = new Promise(function(resolve, reject){

            // 依赖p1的状态,比p1延迟了两个tick即ticke-3执行then

            p3 = new Promise(res => res(p1));

            // 等价于p1.then(tick1).then(tick2).then(logp3)

            p3.then(() => {

                // tick-3

                console.log('p3')

                resolve('ok');

            })

            });

            p1.then(() => {

            // tick-1

            console.log('p1-1')

            }).then(() => {

            // tick-2

            console.log('p1-2')

            }).then(() => {

            // tick-3

            console.log('p1-3')

            })

            p2.then(function(data) {

            // p2在tick-3时resolve则本函数在tick-4执行

            console.log('p2-1')

            }).then(function(data) {

            // tick-5

            console.log('p2-2')

            }).then(function(data) {

            // tick-6

            console.log('p2-3')

            })

            p3.then(function(data) {

            // 与p2内部的then在同一时刻即tick-3

            console.log('p3-1')

            }).then(function(data) {

            // tick-4

            console.log('p3-2')

            }).then(function(data) {

            // tick-5

            console.log('p3-3')

            })

根据不同的tick整理顺序可得:

// tick-1: p1-1

            // tick-2: p1-2

            // tick-3: p3,p3-1,p1-3 【由于p3先入栈tick3任务故在p1-3之前】

            // tick-4: p2-1,p3-2

            // tick-5: p2-2,p3-3

            // tick-5: p2-3

如果把p3部分的代码转换下是等效于下面这段的

const p2 = new Promise(function(resolve, reject){

            // 依赖p1的状态,比p1延迟了两个tick即ticke-3执行then

            const noop = () => void 0;

            p3 = p1.then(noop).then(noop);

            // 等价于p1.then(tick1).then(tick2).then(logp3)

            p3.then(() => {

                // tick-3

                console.log('p3')

                resolve('ok');

            })

            });

例子10:

// 下面是两个例子

// 例子1:

const p1 = new Promise(function (resolve, reject) {

            setTimeout(() => reject(new Error('fail')), 3000)

        })

        const p2 = new Promise(function (resolve, reject) {

            setTimeout(() => {

                console.log('p2')

                resolve(p1)

            }, 1000)

        })

        p2

        .then(result => console.log(result))

        .catch(error => console.log(error))

        // 打印结果:p2,Error:fail

        // 上面代码中,p1是一个 Promise,3 秒之后变为rejected。p2的状态在 1 秒之后改变,resolve方法返回的是p1。由于p2返回的是另一个 Promise,

        // 导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了 2 秒,p1变为rejected,导致触发catch方法指定的回调函数。

        // 注意,调用resolve或reject并不会终结 Promise 的参数函数的执行。

new Promise((resolve, reject) => { // 例子2:

            resolve(1);

            console.log(2);

        }).then(r => {

            console.log(r);

        });

        // 2

        // 1

        // 上面代码中,调用resolve(1)以后,后面的console.log(2)还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,

        // 总是晚于本轮循环的同步任务。

        // 一般来说,调用resolve或reject以后,Promise 的使命就完成了,后继操作应该放到then方法里面,而不应该直接写在resolve或reject的后面。

        // 所以,最好在它们前面加上return语句,这样就不会有意外。

        new Promise((resolve, reject) => {

            return resolve(1);

            // 后面的语句不会执行

            console.log(2);

        })

例子11:

const getJSON = (num)=>(new Promise((resolve,reject)=>resolve(num)))

        getJSON(1).then(function(json) {

            console.log(json)

            return json+1;

        }).then(function(post) {

            console.log(post)

        });

        // 打印:1,2

        const getJSON = (num)=>(new Promise((resolve,reject)=>resolve(num)))

        getJSON(1).then(function(post) {

            return getJSON(2);

        }).then(function (comments) {

            console.log("resolved: ", comments);

        }, function (err){

            console.log("rejected: ", err);

        });

        // 打印:resolved:  2

例子12:重要

promise.then内包含prmise.then,但是内部这个promise前面没有return的情况

new Promise((resolve, reject) => {

            console.log("promise")

            resolve()

        })

        .then(() => {   // 执行.then的时候生成一个promise是给最后一个.then的

            console.log("then1")

            new Promise((resolve, reject) => {

                console.log("then1promise")

                resolve()

            })

            .then(() => {// 执行这个.then的时候,生成的promise是下面一个then的

                console.log("then1then1")

                setTimeout(()=>{

                    console.log('setTimeout')

                },0)

            })

            .then(() => {

                console.log("then1then2")

            })

        })

        .then((res) => {

        // 这个

            console.log("then2",res)

        })

        // 执行结果:promise,then1,then1promise,then1then1,then2 undefined,then1then2,setTimeout

例子13:重要

promise.then内包含prmise.then,但是内部这个promise前面有return的情况

new Promise((resolve, reject) => {

            console.log("promise")

            resolve()

        })

        .then(() => {   // 执行.then的时候生成一个promise是给最后一个.then的

            console.log("then1")

            return new Promise((resolve, reject) => {

                console.log("then1promise")

                resolve()

            })

            .then(() => {// 执行这个.then的时候,生成的promise是下面一个then的

                console.log("then1then1")

                setTimeout(()=>{

                    console.log('setTimeout')

                },0)

            })

            .then(() => {

                console.log("then1then2")

            })

        })

        .then((res) => {

        // 这个

            console.log("then2",res)

        })

        // 注意:.then1函数体有了return返回值,是一个Promise对象,而且是then1then2执行完返回的匿名Promise对象。所以只有等这个Promise对象resolve了之后,才会执行then2回调函数体的逻辑,所以’then2’最后才会打印。

        // 执行结果:promise,then1,then1promise,then1then1,then1then2,then2 undefined,setTimeout

关于例子12和例子13,说说自己的一点观点:内部promise在resolve后立即执行后面的then(其他不是包含promise也是这样),然后会跳出来执行外部promise的一个then,而不是继续执行内部promise的下一个then。如果有return,情况就不一样了。

例子14:难,不懂,待解释

1. 当Promise对象作为resolve的参数时

const p = Promise.resolve();

        const p1 = Promise.resolve(p); //就是p

        const p2 = new Promise(res => res(p)); //新建一个对象,对象状态依赖p

        // res(p)可以看作 await p1; await resolve();

        // 或者p.then(data => getData()).then(() => p2.resolve())

        // 首先;p1 === p; p2!===p

        // 那么,p1是一个fulfilled状态的对象;p2状态需要运行后求得

        console.log(p === p1); // true

        console.log(p === p2); // false

        p1.then(() => {

            console.log('p1-1');

        }).then(() => {

            console.log('p1-2');

        }).then(() => {

            console.log('p1-3');

        })

        p2.then(() => { //p-2.resolve之后才能调用回调函数

            console.log('p2-1');

        }).then(() => {

            console.log('p2-2');

        }).then(() => {

            console.log('p2-3');

        })

        p.then(() => {

            console.log('p-1');

        }).then(() => {

            console.log('p-2');

        }).then(() => {

            console.log('p-3');

        })


        //  运行结果

        // getData()

        // p1-1

        // p-1

        // 前面两个打印因为本身状态已经resolve了,所以直接出结果

        // resolve()

        // p1-2

        // p-2

        // p2-1

        // p1-3

        // p-3

        // p2-2

        // p2-3

        // 后面打印p2-1是等到p运行resolve后才开始打印

例子15:难

2. 当Promise的resolve方法在另一个Promise对象的then方法中运行时,变异步;

例子12和例子13类似:p1要等resolve才能执行后面的then,所以p3先执行了。只要有resolve,就会先执行属于那个resolve的then,然后执行另外一个promise的resolve的then,最后才会继续第一个resolve接下去的then

let p3;

        p1 = new Promise(resolve => {

            p3 = new Promise(res => res());

            p3.then(() => {

                console.log('p3')

                resolve(); // resolve()方法用在then方法中,变为异步执行

            })

        })

        p1.then(() => {

            console.log('p1-1');

        }).then(() => {

            console.log('p1-2');

        })


        p3.then(() => {

            console.log('p3-1')

        }).then(() => {

            console.log('p3-2')

        })

        // 执行结果:p3,p3-1,p1-1,p3-2,p1-2

例子16:

new Promise((r,rj) => {

            console.log('外p');

            r();

        }).then(() => {

            console.log('外then1');

            new Promise(((r,rj) => {

                console.log('内p');

                r();

            })).then(() => {

                console.log('内then1');

                return new Promise((r, rj) => {r();});

            }).then(() => {

                console.log('内then2');

            });

        }).then(() => {

            console.log('外then2');

        }).then(() => {

            console.log('外then3');

        }).then(() => {

            console.log('外then4');

        });

//      return new Promise((r, rj) => {r();})  等同于

//      return new Promise((r, rj) => {r();}).then(()=>{console.log(1)}).then(()=>{console.log(2)}).then(()=>{console.log(3)});

        // 执行结果:外p,外then1,内p,内then1, 外then2,外then3,外then4,内then2,

例子17:------

// 例子1:
// await 不过是generator和promise结合后的一种语法糖

        // await 会生成一个 Promise ,以其后表达式的值 resolve 这个 Promise(类似 Promise.resolve()),并在它的 then 回调里执行 await 返回之后的一切,同时结束程序的执行。

        function doA1(){ 

            new Promise( function (resolve) { 

                console.log(11); 

                resolve(); 

            }).then(o=>{ 

            console.log(12); 

            }).then(o=>{ 

            console.log(13); 

            }).then(o=>{ 

            console.log(14); 

            }) 

        } 


        await doA1(); 

        console.log(2);

        //执行结果顺序为 11 12 2 13 14

        // 按代码执行顺序,首先初始事件循环:

        // 1.Promise 的 executor 参数是立即执行的,所以马上打印 11。

        // 2.因为马上 resolve 了,后面跟着 then 故 promise 进入微事件队列中,继续执行其它平台代码。

        // 3.await 因为跟了一个非 Promise 的值所以会自动包上一层 Promise.resolve,即无论如何都会至少等一个微事件周期。所以得到的 undefined 也进入微事件队列。

        // await 阻塞了,本事件循环准备结束,开始清微事件队列

        // 1.先是前面 11 得到的 promise,处理 then 回调打印 12,后面的 promise 继续入微事件队列。

        // 2.接着是 await 得到 undefined,因为没有赋值,被丢弃。

        // 3.await 得到了值,不再阻塞,继续往下执行打印 2。

        // 4.await 后的平台代码执行完毕,微事件队列中还有 12 得到 promise。

        // 5.重复上边过程打印 13 和 14

        // 6.微事件队列已清空,本事件循环结束。

// 例子2:

        // 返回了 Promise 那么 await 就会等这个 Promise 都 resolve 了才会继续往下执行。

        function doA1(){

            return new Promise( function (resolve) {

                console.log(11);

                resolve();

            }).then(o=>{

            console.log(12);

            }).then(o=>{

            console.log(13);

            }).then(o=>{

            console.log(14);

            })

        }

        await doA1();

        console.log(2);

        //执行结果顺序为 11 12 13 14 2

例子18:难

new Promise((r,rj) => {

            console.log('外p');

            r();

        }).then(() => {

            console.log('外then1');

            new Promise(((r,rj) => {

                console.log('内p');

                r();

            })).then(() => {

                console.log('内then1');

                return new Promise((r, rj) => {r();});

            }).then(() => {

                console.log('内then2');

            });

        }).then(() => {

            console.log('外then2');

        }).then(() => {

            console.log('外then3');

        }).then(() => {

            console.log('外then4');

        });

//      return new Promise((r, rj) => {r();})  等同于

//      return new Promise((r, rj) => {r();}).then(()=>{console.log(1)}).then(()=>{console.log(2)}).then(()=>{console.log(3)});

        // 执行结果:外p,外then1,内p,内then1, 外then2,外then3,外then4,内then2,

例子19:

const p1 = new Promise( (resolve,reject) => {

            setTimeout(() => {

                reject(new Error('fail'))

                console.log('3s')  // console.log语句仍然会执行,并且在reject()异步函数 前执行

            },3000)

        })

        const p2 = new Promise( (resolve,reject) => {

            setTimeout( () => {

                return resolve(p1)  // 一般都在这里加return,这样后面的代码就不会执行,防止意外!!

                console.log('1s')

            }, 1000 )

        })

        p2.then(res => console.log(res))    // 并没有执行

        .catch(error => console.log(error))

        // 打印结果:3s,Error:fail

        // 注意: p2.then(res => console.log(....))并没有执行,因为p2的状态变成了p1的状态,是rejected

        // p2.then(res => console.log(res,'fulfilled'), res => console.log(res,'rejected'))

        // 实际执行的是上面的 第二个回调函数

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容