关于javascript中的promise的用法和注意事项

更新日期: 2020-10-16阅读: 1.1k标签: promise

一、promise描述

promise是javascript中标准的内置对象,用于表示一个异步操作的最终状态(是失败还是成功完成)及其结果值。它让你能够把异步操作最终成功或者失败的原因和响应的处理程序相关联,也就是说通过promise你可以自定义异步操作结束后该做什么。这样的话异步方法就和同步方法很类似,也有返回值,只不过这个返回值不是立即返回最终的值,而是返回一个promise,当promise的状态发生改变时,就会触发相应的处理程序。

一个promise无论什么时候都必然处于以下几种状态:1、待定(pending) 2、已兑现(fulfilled) 3、已拒绝(rejected)

promise创建之初是待定状态,它既咩有被兑现也咩有被拒绝,它用于包装还没有被添加promise支持的函数,包装后的函数变成异步操作函数,当操作结束时,会有两个两个分支,一个是已兑现,一个是已拒绝,如下图。已兑现状态的promise会调用后续的then方法,而已拒绝状态的promise既可以调用then方法,也可以被catch方法捕捉到。为什么then方法可以捕捉两个状态的promise呢?这里先不讲,下面再详细介绍。



二、promise 的流程走向

上图是promise的流程图,从左到右可以得知一个promise在待定状态时通过两个分支走向分别进入then方法或者catch方法,这两个c方法都会返回promise,如果这个promise也被敲定了,而且其后也有then方法或者catch方法,则又会进入后续的then和catch中,直至咪有。

也就是说,promise和then或者catch可以形成一个异步操作的链式结构,结合js的事件循环机制,这使得js的优势更加明显,发展至今仍能在浏览器上频繁看到它的身影。

我们要注意流程的特点:

1、promise是对象,它的转移成功不取决于返回值,而取决于状态的敲定(是成功还是失败)

2、then和catch是函数,只要有promise状态发生了改变,该promise对应后面的then或者catch方法就会被调用,而这两个方法本身会返回一个promise,这个返回的promise又会影响这两个方法后面的then或者catch方法。两个方法的返回值一定是promise。


三、promise的创建

Promise 对象是由关键字 new 及其构造函数来创建的。该构造函数会把一个叫做“处理器函数”(executor function)的函数作为它的参数。这个“处理器函数”接受两个函数——resolve 和 reject ——作为其参数。当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。示例如下:

let myFirstPromise = new Promise(function(resolve, reject){
    //当异步代码执行成功时,我们才会调用resolve(...), 当异步代码失败时就会调用reject(...)
    //在本例中,我们使用setTimeout(...)来模拟异步代码,实际编码时可能是XHR请求或是html5的一些api方法.
    setTimeout(function(){
        resolve("成功!"); //代码正常执行!
    }, 250);
});

myFirstPromise.then(function(successMessage){
    //successMessage的值是上面调用resolve(...)方法传入的值.
    //successMessage参数不一定非要是字符串类型,这里只是举个例子
    console.log("Yay! " + successMessage);
});

四、promise的优势

在promise未出现时,如果我们调用异步代码块的话是没有办法保持顺序的,而如果又出现了异步代码结果之间按序的需求,该如何实现呢?

以前的话通常都会将异步代码一层一层地内嵌来实现异步代码按序实现,但是这就造成了代码维护困难,开发难度增大

doSomething(function(result) {
  doSomethingElse(result, function(newResult) {
    doThirdThing(newResult, function(finalResult) {
      console.log('Got the final result: ' + finalResult);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);

这就是经典的回调地狱。而如果使用了前面介绍的promise,那么代码就变成了容易维护的链式结构


五、then方法返回的promise类型

当一个 Promise 完成(fulfilled)或者失败(rejected)时,返回函数将被异步调用(由当前的线程循环来调度完成)。具体的返回值依据以下规则返回。如果 then 中的回调函数:

返回了一个值,那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。

没有返回任何值,那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined。

抛出一个错误,那么 then 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。

返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。

返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。

返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。


 六、catch捕捉的错误

catch能捕捉promise组合中出现的错误,但是有两种错误不能捕捉:

1、已决议的错误不能捕捉

//创建一个新的 Promise ,且已决议
var p1 = Promise.resolve("calling next");

var p2 = p1.catch(function (reason) {
    //这个方法永远不会调用
    console.log("catch p1!");
    console.log(reason);
});

p2.then(function (value) {
    console.log("next promise's onFulfilled"); /* next promise's onFulfilled */
    console.log(value); /* calling next */
}, function (reason) {
    console.log("next promise's onRejected");
    console.log(reason);
});

2、异步函数中抛出的错误不能捕捉

需要注意的是,作者亲手实践发现:promise包裹的异步函数执行成功后必须显式地调用resolve和reject方法才能触发后续then和catch方法,如果promise方法包裹的不是异步函数,是普通的同步函数,如果该同步代码运行出错,即便没有调用reject方法时,后面的catch方法仍然能够捕捉到这个错误,但如果同步代码没有出错,没有显式调用resolve方法转移的话,后续的then方法不会触发。


七、高级示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 10px;
        }
        html{
            width: 100%;
            height: 100%;
        }
        body{
            width: 100%;
            height: 100%;
            display:flex;
            align-items: center;
            justify-content: center;
        }
        div.displaydatabox{
            width: 300px;
            height: 300px;
            border-radius: 50px;
            text-align: center;
            line-height: 300px;
            box-shadow: 0 0 10px 2px black;
        }
        div.button{
            width: 100px;
            height: 50px;
            border-radius: 21px;
            border: 2px solid orange;
            line-height: 50px;
            text-align: center;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="button">创建</div>
    <div class="button">输入文字</div>
    <div class="button">消失</div>
    <script lang="javascript">
        let buttonlist=document.querySelectorAll("div.button");
        let body=document.querySelector("body");
        buttonlist[0].onclick=function()
        {
            let div=document.createElement("div");
            div.className="displaydatabox";
            body.appendChild(div);
        }
        buttonlist[2].onclick=function()
        {
            let div=document.querySelector("div.displaydatabox");
            body.removeChild(div);
        }
        buttonlist[1].onclick=function(e)
        {
            let p1=new Promise((resolve,reject)=>
            {
                setTimeout(()=>{//用setTimeout函数模拟异步函数
                    let div=document.querySelector("div.displaydatabox");
                    div.textContent="这是promise实验";
                    //reject(1);
                    resolve(1);//调用resolve将调用第一个then
                },2000);
            }).then(function(resolve){
                return new Promise((resolve,reject)=>{
                    console.log("这是状态咩有敲定的promise,所以不会调用后面所有的then方法");
            //resolve(1)//没有调用resolve或者reject,所以状态未敲定。如果调用,将输出1和finally it has been called!! }) .then(function(e){ console.log(e); }); }).catch(function(e) { console.log(e+" 没有块可以输入!!"); }).then(()=> { console.log("finally it has been called!!"); }) } </script> </body> </html>

 

链接: https://www.fly63.com/article/detial/10071

你真的了解 Promise 吗?Promise 必知必会(十道题)

Promise 想必大家十分熟悉,想想就那么几个 api,可是你真的了解 Promise 吗?本文根据 Promise 的一些知识点总结了十道题,看看你能做对几道。

剖析Promise内部结构,一步一步实现一个完整的、能通过所有Test case的Promise类

本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,Promise标准中仅指定了Promise对象的then方法的行为,其它一切我们常见的方法/函数都并没有指定.

Async/Await替代Promise的6个理由

Async/Await替代Promise的6个理由:Async/Await是近年来JavaScript添加的最革命性的的特性之一。它会让你发现Promise的语法有多糟糕,而且提供了一个直观的替代方法。

Promise 原理解析与实现(遵循Promise/A+规范)

Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一,Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数

简单模仿实现 Promise 的异步模式

这篇文章是考虑如何自己实现一个简单 Promise,用以理解 Promise。和原生 Promise的调用方法一样,支持链式调用,本文实现的方法只能用于参考Promise的原理,还有很多特性没有实现,比如 race,all 方法的实现。

数组的遍历你都会用了,那Promise版本的呢

在对数组进行一些遍历操作时,发现有些遍历方法对Promise的反馈并不是我们想要的结果。async/await为Promise的语法糖,文中会直接使用async/await替换Promise;map可以说是对Promise最友好的一个函数了,

Promise使用时应注意的问题

最近在使用axios库时遇到了个问题,后端接口报了500错误,但前端并未捕获到。在axios整体配置的代码中,过滤http code时,调用了filter401()、filter500(),但是这里注意并未将两个filter函数的结果返回,也就是并未返回promise,这就是导致问题出现的原因

es6 Promise 的基础用法

想必接触过Node的人都知道,Node是以异步(Async)回调著称的,其异步性提高了程序的执行效率,但同时也减少了程序的可读性。如果我们有几个异步操作,并且后一个操作需要前一个操作返回的数据才能执行

关于 Promise 的 9 个提示

你可以在 .then 里面 return 一个 Promise,每次执行 .then 的时候都会自动创建一个新的 Promise,对调用者来说,Promise 的 resolved/rejected 状态是唯一的,Promise 构造函数不是解决方案,使用 Promise.resolve

手写一款符合Promise/A+规范的Promise

Promise的一些用法在此不多赘述,本篇主要带领你手写一个Promise源码,学完你就会发现:Promise没有你想象中的那么难.本篇大概分为以下步骤:实现简单的同步Promise、增加异步功能、增加链式调用then、增加catch finally方法、增加all race 等方法、实现一个promise的延迟对象defer、最终测试

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!