promise

Promise按照用途来解释:

主要用于异步运算。

可以将异步操作队列化,按照期望的顺序执行,返回符合期望的结果。

可以在对象之间传递和操作Promise,帮助我们处理队列。

Promise产生的原因:

Javascript中包含大量异步操作。

创造它的首要目标是操作DOM。

所以,Javascript的操作大多是异步的。

浏览器中的Javascript

异步操作以 事件为主。

回调主要出现在Ajax和File API 。

异步回调的问题:

嵌套层次很深,难以维护。

无法正常使用return和throw。

无法正常检索堆栈信息。

多个回调之间难以建立联系。

下面是Promise的模型简介:

new Promise(
    /*执行器executor*/
    function (resovle, reject) {
        resovle();
        reject();
    }
)
    .then(function A() {
        //成功,下一步
    }, function B() {
        //失败,做响应处理
    })

从上面代码可以看出:

Promise 是一个代理对象,它和原先要进行的操作并无关系。

它通过引入一个回调,避免更多的回调。

Promise有3个状态:

  • pendding[待定] 初始状态
  • fulfilled[实现]操作成功
  • rejected[被否决]操作失败

当Promise状态发生变化 ,就会触发.then() 里的相应函数处理后续步骤。

Promise状态一经改变,不会再变。

接下来这张图片是Promise执行的过程

image-20200307111725436

每个then执行完了之后,都会返回一个Promise对象,然后再调用下一个then,直到所有的then都处理完。

最简单的实例:

console.log('here we go');
new Promise(resolve => {
    console.log("execute start");
    setTimeout(() => {
        resolve('hello');
    }, 2000)
}).then(value => {
    console.log(value + ' resolve world');
});

代码的执行结果为

here we go

execute start

hello resolve world

这样可以直观的看出then函数是等执行器执行结束才会执行的。

两步执行的范例:分2次,顺序依次执行

console.log('here we go');
new Promise(resolve => {
    console.log("execute start");
    setTimeout(() => {
        resolve('hello');
    }, 2000)
}).then(value => {
    console.log(value + ' resolve world');
    return new Promise(resolve => {
        setTimeout(() => {
            resolve('world');
        }, 2000)
    })
}).then(value => {
    console.log(value + ' world');
});

代码的执行结果为:

here we go

execute start

hello resolve world

world world

从上面例子可以看出,promise是会顺序执行每个then的。

当promise里面的状态一旦发生变化,会调用then,

然后then会生成一个新的promise,每次promise其实传递的只有一个状态,(resolve或者reject),

紧接着then会接收到这个状态函数里面传递的数值。

promise用自己的回调解决了多个回调函数嵌套的问题

假设一个Promise已经完成了,再.then()会怎样?

console.log('start');
let promise = new Promise(resolve => {
    setTimeout(() => {
        console.log('the promise fulfilled');
        resolve('hello, world');
    }, 1000);
});

setTimeout(() => {
    promise.then(value => {
        console.log(value);
    })
}, 3000)

输出结果为:

start

the promise fulfilled

hello, world

在任何一个地方生成了promise队列后,如果我们的队列是先进先出的状态,队列会按顺序执行,后面追加的then,也会接受到前面promise返回的值。

假设在.then()的函数里面不返回新的Promise,会怎样?

console.log('start');
new Promise(resolve => {
    setTimeout(() => {
        resolve('hello');
    })
})
    .then(value => {
        console.log(value);
        console.log('everyone');
        (function () {
            return new Promise(resolve => {
                setTimeout(() => {
                    console.log('Mr laure');
                    resolve('Merry XmaS');
                }, 2000);
            })
        }())
        return false;
    })
    .then(value => {
        console.log(value + ' world');
    });

输出结果为:

start

hello
everyone
false world

Mr laure

上面的代码可以看出,第一个then函数里面有一个立即执行的函数,是在2s之后返回一个promise对象,但是先返回了false,就会调用第2个then;

因为第2个then没有返回新的值,返回的promise是在立即执行的函数里返回的,而不是在then的响应函数里面返回的,then返回的promise实例就没有等待里面的函数完成,而是在返回了false之后,直接调用了下面那个then,false被传递给了第2个then函数。

在promise里面,如果不直接返回一个promise实例,会默认执行下一个环节,即使返回了false,如果没有传递值,第2个then里面的value就是undefined,仍然不影响promise往下执行。

引出.then()

.then()接收两个函数作为参数,分别代表fulfilled和rejected

.then()返回一个新的Promise实例,所以它可以链式调用

当前面的Promise状态改变时,.then()根据其最终状态,选择特定的状态响应函数执行。

状态响应函数可以返回新的Promise,或者其他值。

如果返回新的Promise,那么下一级.then() 会在新Promise状态改变之后执行。

如果返回其他任何值,则会立刻指向下一级.then()

then的嵌套

因为.then()返回的还是Promise实例。

会等里面的.then()执行完,再执行外面的。

对于我们来说,此时最好将其展开,会更好读。

如下代码:then里面又嵌套几个then

console.log('start');
new Promise(resolve => {
    setTimeout(() => {
        resolve(100);
    }, 1000)
})
    .then(value => {
        return new Promise(resolve => {
            console.log('1-1');
            setTimeout(() => {
                resolve(110);
            }, 1000)
        })
            .then(value => {
                console.log('step 1-2');
                return value;
            })
            .then(value => {
                console.log('step 1-3');
                return value;
            });
    })
    .then(value => {
        console.log(value + ' world');
    });

输出结果为:

start

1-1

step 1-2

step 1-3

110 world

看结果可以得出,then里面嵌套的then都是逐步执行的,value会一级一级往下传递,但是不建议then里面嵌套then的方式来写代码,这样感觉看起来不是很友好,展开then里面的then(),下面的方式会友好 一点。

console.log('start');
new Promise(resolve => {
    setTimeout(() => {
        resolve(100);
    }, 1000)
})
    .then(value => {
        return new Promise(resolve => {
            console.log('1-1');
            setTimeout(() => {
                resolve(110);
            }, 1000)
        })
    })
    .then(value => {
        console.log('step 1-2');
        return value;
    })
    .then(value => {
        console.log('step 1-3');
        return value;
    })
    .then(value => {
        console.log(value + ' world');
    });

接下来,看看下面四种Promise的区别:

image-20200309111503853

image-20200309111721464

image-20200309111804276

image-20200309112034099

image-20200309113012322

错误处理

Promise会自动捕获内部异常,并交给rejected响应函数处理。

console.log('start');
new Promise(resolve => {
    setTimeout(() => {
        throw new Error('bye');
    }, 1000);
})
    .then(value => {
        console.log(value + 'world')
    })
    .catch(error => {
        console.log('Error:', error.message);
    });

image-20200309113626653

console.log('start');
new Promise(resolve => {
    setTimeout(() => {
        throw new Error('bye');
    }, 1000);
})
    .then(value => {
        console.log(value + 'world')
    }, value => {
        console.log('Error: ', value);
    });

推荐用第一种方式,用catch的方式来整体捕获错误。

错误和then连用

catch也会返回promise实例,如果返回的过程中没有发生错误的时候,下面的then会依次执行,如果抛出了异常,下面的then会忽略

注意:强烈建议在所有队列最后都加上.catch(),以避免漏掉错误处理造成意想不到的问题。

image-20200309114323336

Promise常用函数:

Promise.all() 函数和.map()函数连用

posted @ 2020-03-25 10:27  melimeli  阅读(160)  评论(0编辑  收藏  举报