Promise初步了解

21 篇文章 14 订阅

什么是Promise

Promise对象是一个构造函数

Promise是异步编程的一种解决方案

promise有几个状态

promise状态有pending、resolve、reject(未决定,履行,拒绝),同一时间只能存在一种状态,且状态一旦改变就不能再变

  • 1.初始化状态:pending
  • 2.成功状态,调用resolve
  • 3.失败状态,调用reject

promise的优缺点

优点
​ 1.Promise 分离了 异步数据获取 和 业务逻辑,有利于代码复用。
​ 2.可以采用链式写法,避免回调地狱。

缺点:​
1.代码逻辑顺序与执行顺序不一致,不利于阅读与维护
2. 一旦新建它就会立即执行,无法中途取消
3. 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
4. 当处于padding状态时,无法获取到底是处于哪个阶段,是刚开始还是已经结束。

promise是异步不是同步

promise本身是同步
Promise作用:解决异步回调的问题

promise简介

  1. promise简单例子
function test(resolve, reject) {
    var timeOut = Math.random() * 2;
    setTimeout(function () {
        if (timeOut < 1) {
            log('call resolve()...');
            resolve('200 OK');
        }
        else {
            log('call reject()...');
            reject('timeout in ' + timeOut + ' seconds.');
        }
    }, timeOut * 1000);
}
var p1 = new Promise(test);
var p2 = p1.then(function (result) {
    console.log('成功:' + result);
});
var p3 = p2.catch(function (reason) {
    console.log('失败:' + reason);
});

变量p1是一个Promise对象,它负责执行test函数。由于test函数在内部是异步执行的,当test函数执行成功/失败时,我们告诉Promise对象

上面代码可简化为

function test(resolve, reject) {
    var timeOut = Math.random() * 2;
    setTimeout(function () {
        if (timeOut < 1) {
            log('call resolve()...');
            resolve('200 OK');
        }
        else {
            log('call reject()...');
            reject('timeout in ' + timeOut + ' seconds.');
        }
    }, timeOut * 1000);
}
new Promise(test).then(function (result) {
    console.log('成功:' + result);
}).catch(function (reason) {
    console.log('失败:' + reason);
});

可见Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了

resolve方法是把状态设置为成功,执行then方法
reject方法是把状态设置为失败,执行catch方法

  1. Promise还可以做多层嵌套,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务(任务1或任务2)失败则不再继续,并执行错误处理函数。
    要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:
       //异步方法一
        function getone(resolve,reject){
            setTimeout(function(){
                resolve("gettwo");
            },3000)
        }
        //异步方法二
        function gettwo(resolve,reject){
            setTimeout(function(){
                resolve("getthree");
            },3000)
        }
        //异步方法三
        function getthree(resolve,reject){
        	var ran = 0;
            setTimeout(function(){
            	let ranStr = Math.random().toFixed(2);
                ran = Number(ranStr);
                console.log('---------------');
                console.log(ran)
                if(ran>0.5) reject("getthree");
                else resolve('getthree');
            },3000)
        }
        
        var result = new Promise(getone)
        .then(function(resulttwo){
            console.log('----------two------------');
            console.log(resulttwo);
            return new Promise(getthree);
        })
        .then(function(resultthree){
            console.log('-----------three---------');
            console.log(resultthree);
        })
        .catch(function(err){
        	console.log('-----------error---------');
            console.log(err);
        })
  1. Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。
var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
// 同时执行p1和p2,并在它们都完成后执行then:(同时满足多个条件后才执行结果函数)
Promise.all([p1, p2]).then(function (results) {
    console.log(results); // 获得一个Array: ['P1', 'P2']
});

Promise的六大方法

  1. Promise.resolve
    静态方法Promise.resolve(value)可以认为是new Promise()方法的快捷方式,比如Promise.resolve(42)可以认为是以下代码的语法糖:

    new Promise(function(resolve){
      resolve(42)
    })
    

    这个静态方法会让Promise对象立即进入resolved 状态,并将参数传递给后面then方法。

    简单总结一下Promise.resolve方法的话,它的作用就是将传递给它的参数填充到promise对象后并返回这个promise对象。

  2. Promise.reject
    Promise.reject(error)是和Promise.resolve(value)类似的静态方法,是new Promise()方法的快捷方式。比如Promise.reject(new Error(“出错了”))就是下面代码的语法糖形式:

     new Promise(function(resolve,reject){
         reject(new Error("出错了"));
     });
    

    简单总结一下Promise.reject方法的话:它的功能是调用该promise对象通过then指定的onRejected函数,并将错误(Error)对象传递给这个onRejected函数

  3. Promise.then
    promise.then(onFulfilled, onRejected)

    ① 回调函数异步执行

    var promise = new Promise(function (resolve){
        console.log("inner promise"); // 1
        resolve(42);
    });
    promise.then(function(value){
        console.log(value); // 3
    });
    console.log("outer promise"); // 2
    

    ② 返回值 ----- 新创建的Promise对象

    不管你在回调函数onFulfilled中会返回一个什么样的值,或者不返回值,该返回值都会由Promise.resolve(return的返回值)进行相应的包装处理,因此,最终then的结果都是返回一个新创建的promise对象。正是then函数中有了这样返回值的机制,才能使得在整个Promise链式结构当中,每个then方法都能给下一个then方法传递参数

    var aPromise = new Promise(function (resolve) {
      resolve(100);
    });
    var thenPromise = aPromise.then(function (value) {
      console.log(value);
    });
    var catchPromise = thenPromise.catch(function (error) {
      console.error(error);    //不执行
    });
    

    ③ promise穿透
    我们先来举个例子:

    Promise.resolve('foo').then(Promise.resolve('bar')).then(function (result) {
      console.log(result);
    });
    

    如果你认为输出的是 bar,那么你就错了。实际上它输出的是 foo!

    产生这样的输出是因为你给then方法传递了一个非函数(比如promise对象)的值,代码会这样理解:then(null),因此导致前一个promise的结果产生了坠落的效果,也就是和下面的代码是一样的,代码直接穿透了then(null)进入了下一层链:

    Promise.resolve('foo').then(null).then(function (result) {
      console.log(result);
    });
    
  4. Promise.catch

    相当于promise.then(onFulfilled, onRejected)中的onRejected函数

  5. Promise.race()实现:「谁跑的快,以谁为准执行回调」
    使用案例:比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作

    //请求某个图片资源
    function requestImg(){
        var p = new Promise(function(resolve, reject){
            var img = new Image();
            img.onload = function(){
                resolve(img);
            }
            img.src = 'xxxxxx';
        });
        return p;
    }
    
    //延时函数,用于给请求计时
    function timeout(){
        var p = new Promise(function(resolve, reject){
            setTimeout(function(){
                reject('图片请求超时');
            }, 5000);
        });
        return p;
    }
    
    Promise
    .race([requestImg(), timeout()])
    .then(function(results){
        console.log(results);
    })
    .catch(function(reason){
        console.log(reason);
    });
    

race方法,执行较快的那个,执行then()。执行较慢的那个,执行结果将被丢弃。

  1. Promise.all

    Promise.all接收一个promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用.then方法。

    传递给Promise.all的promise并不是一个个的顺序执行的,而是同时开始、并行执行的,我们可以举个例子:

    let arr = [1000, 3000, 5000, 7000]
    let promiseArr = []
    
    for(let i = 0; i < arr.length; i++ ) {
      let newPromise = new Promise((resolve, reject) => {
        setTimeout(()=> {
          console.log(arr[i])
          resolve(arr[i])
        }, arr[i])
      })
      promiseArr.push(newPromise)
    }
    
    Promise.all(promiseArr).then(res => {
      console.log(res)
    }).catch(err =>{
      console.log(err)
    })
    

    如果所有的Promise中只有一个执行错误,那么整个Promise.all不会走Promise.all().then()这个流程了,而是走Promise.all().catch()这个流程

异常捕获的三种方法

  • then函数中传递第二个函数作为第二个参数,用来执行reject函数
  • catch函数
  • finally ,不论成败,resolve/reject,最后都会执行
 //捕获异常一,then中传递第二个函数,用来执行reject函数
 new Promise((resolve,reject)=>{
  	let random = parseInt(Math.random()*10);
  	setTimeout(()=>{
  		if(random>=9) resolve(random);
  		else reject(random)
  	})
  }).then((val)=>{
  	let pow2 = Math.pow(val,2);
  	console.log('success',pow2)
  },(err)=>{
  	console.log('error',err);
  })
  
  
  //捕获异常二,catch函数
  new Promise((resolve,reject)=>{
  	let random = parseInt(Math.random()*10);
  	setTimeout(()=>{
  		if(random>=9) resolve(random);
  		else reject(random)
  	})
  }).then((val)=>{
  	let pow2 = Math.pow(val,2);
  	console.log('success2',pow2)
  }).catch((err)=>{
  	console.log('error2',err);
  })
  
  // finally 最后执行 
  new Promise((resolve,reject)=>{
  	let random = parseInt(Math.random()*10);
  	setTimeout(()=>{
  		if(random>=6) resolve(random);
  		else reject(random)
  	})
  }).then((val)=>{
  	let pow2 = Math.pow(val,2);
  	console.log('success3',pow2)
  }).catch((err)=>{
  	console.log('error3',err);
  }).finally(()=>{
  	console.log('finally,不论成败,都会执行!')
  })

Promise链式调用中then/catch方法的返回值

1、概述

then() 方法返回一个 Promise对象
它最多需要有两个参数:Promise 的成功和失败情况的回调函数。

const promise1 = new Promise((resolve, reject) => {
  resolve('Success!');
  //reject('fail');
});

promise1.then((value) => {    // 成功回调
  console.log(value);
},(err)=>{                        //失败回调
   console.log(err);
});
2、then() 方法的返回值

如果 then 中的回调函数:

  • 返回了一个值,或没有返回任何值(undefined),那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。即相当于返回 Promise.resolve(返回的值/undefined)

    Promise.resolve(33).then((data)=>{ 
       console.log(data)       //  33
       return 100;
    }).then((val)=>{ 
       console.log(val) ;   // 100
    }).then((res)=>{
        console.log(res);    // undefined
    })
    

    最终整体返回一个Promise对象

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

    Promise.resolve(33).then((data)=>{ 
       throw "error";       // 抛出错误,执行reject
    }).then((val)=>{ 
       console.log(val) ;   //不执行
    }).then((res)=>{
        console.log(res);    //不执行
    }).catch(err=>{
        console.log(err) ;    // error  未捕获到错误之前的不执行,捕获到错误,然后继续向下执行
        return "success";
    }).then(res=>{      
       console.log(res);    // success
    })
    

扔出错误(throw ''),则在错误被捕获之前的代码将不执行,一旦错误被捕获,则继续向下执行。

  • 返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
    let p1 = new Promise((resolve,reject)=>{
         setTimeout(()=>{
              resolve('timeout')
         },5000)
    })
    Promise.resolve(33).then((data)=>{ 
      return p1;
    }).then(res=>{      
       console.log(res);    // 打印 timeout
    })
    
  • 返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
    let p1 = new Promise((resolve,reject)=>{
         setTimeout(()=>{
              reject('error')
         },5000)
    })
    Promise.resolve(33).then((data)=>{ 
      return p1;
    }).then(res=>{      
       console.log(res);    // 不执行
    }).catch((err)=>{
      console.log(err);   // 打印 error
    })
    
  • 返回一个未定状态(pending)的 Promise,那么then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。
    let p1 = new Promise((resolve,reject)=>{
         setTimeout(()=>{
             console.log('5000s');
         },5000)
    })
    Promise.resolve(33).then((data)=>{ 
      return p1;
    }).then(res=>{      
       console.log(res);    // 不执行
    }).catch((err)=>{
      console.log(err);   // 不执行
    }).finally(()=>{
      console.log(123)   // 不执行
    })
    
    返回的Promise也是pending状态
    在这里插入图片描述

参考链接:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

如何生成一个Promise对象

// 方法一,new Promise(异步函数) 
let p1 = new Promise(resolve => {
  resolve('成功1!');
});

// 方法二,Promise.resolve(值) ,返回一个promise对象
let p2 = Promise.resolve('成功2!');

function printContent(params) {
  console.log(params);
}
p1.then(printContent);
p2.then(printContent);

如何中断Promise的链式调用

  • 方法一、通过抛出一个异常来终止,即throw 一个异常

    当Promise链中抛出一个异常时,错误信息沿着链路向后传递,直至被捕获,错误捕获前的函数不会被调用。
    但是如果错误被捕获后,其后面还有链式调用时,仍然会被调用

    链式调用的最后捕获错误,用来终止调用

    let needBreak = true;
    let p = new Promise((resolve, reject) => {
      resolve('step1');
    });
    
    p.then(data => {
      console.log(data);
      return 'step2';
    }).then(data => {
      console.log(data);
      if (needBreak) {
        throw "we need break";     // 抛出异常
      }
      return 'step3';
    }).then(data => {
      console.log(data);
      return 'step4';
    }).catch(reason => {      // 接收异常消息
      console.log('got error:', reason);
    }).finally(() => {       // 不论成败,才会执行
      console.log('finished.');
    });
    

    这时候的输出就成了这样,没有输出step3
    在这里插入图片描述

链式调用的中间和最后都去捕获错误
(抛出的错误,在被捕获之前,所有的链式调用都不会被调用,但一旦被捕获,之后的链式调用则仍然可以调用),案例如下:

Promise.resolve().then(() => {
    console.log('ok1')
    throw 'throw error1'                // 抛出异常1
}).then(() => {
    console.log('ok2')
}, err => {     
    console.log('err->', err)            // 捕获错误1,继续向下执行
}).then(() => {   
    // 该函数将被调用
    console.log('ok3')
    throw 'throw error3'                // 再次抛出异常2
}).then(() => {
    console.log('ok4')                   // 错误捕获前的函数不会被调用
}).catch(err => {
    console.log('err->', err)          //捕获错误2
})

输出如下
在这里插入图片描述

  • 方法二、通过返回一个Promise.reject() 来中断

    let needBreak = true;
    let p = new Promise((resolve, reject) => {
      resolve('step1');
    });
    
    p.then(data => {
      console.log(data);
      return 'step2';
    }).then(data => {
      console.log(data);
      if (needBreak) {
        return Promise.reject('break without exception.');     // 返回一个 Promise.reject() 异常
      }
      return 'step3';
    }).then(data => {
      console.log(data);
      return 'step4';
    }).catch(reason => {
      console.log(reason);
    }).finally(() => {
      console.log('finished.');
    });
    

    这时候的输出就成了这样,没有输出step3
    在这里插入图片描述

  • 方法三、利用,当新对象保持“pending”状态时,原Promise链将会中止执行

    Promise.resolve().then(() => {
        console.log('ok1')
        return new Promise(()=>{})  // 返回“pending”状态的Promise对象
    }).then(() => {
        // 后续的函数不会被调用
        console.log('ok2')
    }).catch(err => {
        console.log('err->', err)
    })
    

    结果如下在这里插入图片描述

  • 方法四、Promise.race竞速方法

    let p1 = new Promise((resolve, reject) => {
        resolve('ok1')
    })
    
    let p2 = new Promise((resolve, reject) => {
        setTimeout(() => {resolve('ok2')}, 10)
    })
    
    Promise.race([p2, p1]).then((result) => {
        console.log(result) //ok1
    }).catch((error) => {
        console.log(error)
    })
    
    

    结果如下:
    在这里插入图片描述

旧浏览器没有 Promise 怎么办

可以使用es6-promise-polyfill来作兼容。
es6-promise-polyfill可以使用页面标签直接引入,当然也可以通过es6的 import方法引入。

引入这个 es6-promise-polyfill之后,它会在 window对象中加入 Promise对象。这样我们就可以全局使用Promise了

作者:小马_vh
链接:https://juejin.im/post/6844903830119792647
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

参考链接:https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014345008539155e93fc16046d4bb7854943814c4f9dc2000#0

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Promise 是 JavaScript 中处理异步操作的一种方式。它是一个代表了异步操作最终完成或失败的对象。Promise 提供了更优雅和灵活的方式来处理异步操作,避免了回调地狱(callback hell)的问题。 以下是关于 Promise 的一些重要概念和用法: 1. 状态(State):Promise 有三种状态:pending(进行中)、fulfilled(已完成)和 rejected(已拒绝)。初始状态为 pending,当异步操作执行成功时,状态会变为 fulfilled,当异步操作执行失败时,状态会变为 rejected。状态一旦改变,就不会再改变。 2. 执行器(Executor):Promise 的构造函数接受一个执行器函数作为参数。执行器函数在 Promise 被创建时立即执行,用于执行异步操作,并且可以调用 resolve 方法来将 Promise 状态改为 fulfilled,或者调用 reject 方法将 Promise 状态改为 rejected。 3. then 方法:Promise 实例具有 then 方法,用于注册处理异步操作成功或失败的回调函数。then 方法接受两个参数:onFulfilled(处理成功的回调函数)和 onRejected(处理失败的回调函数)。它们都是可选的,并且可以链式调用多个 then 方法。 4. catch 方法:Promise 实例具有 catch 方法,用于注册处理 Promise 拒绝的回调函数。它相当于调用 then 方法的第二个参数。 5. Promise 链(Promise Chaining):通过返回一个新的 Promise 实例,可以在 then 方法中构建 Promise 链。这样可以对多个异步操作进行顺序控制和处理。 6. Promise.all 方法:Promise.all 方法接受一个 Promise 实例的数组,并返回一个新的 Promise 实例。返回的 Promise 实例在数组中所有 Promise 实例都 fulfilled 时才会 fulfilled,否则只要有一个 Promise 实例被 rejected,就会立即被 rejected。 7. Promise.race 方法:Promise.race 方法接受一个 Promise 实例的数组,并返回一个新的 Promise 实例。返回的 Promise 实例在数组中任意一个 Promise 实例 fulfilled 或 rejected 时,就会立即被 resolved。 Promise 是一种强大且灵活的异步编程工具,它简化了异步操作的处理和管理。通过使用 Promise,可以更清晰地组织异步代码,并处理成功和失败的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值