Promise对象

Promise对象

JavaScript是单线程的语言,通过维护执行栈与任务队列而实现了异步操作,setTimeoutAjax就是典型的异步操作,Promise就是异步操作的一个解决方案,用于表示一个异步操作的最终完成或失败及其结果值,Promise有各种开源实现,在ES6中被统一规范,由浏览器直接支持。

语法

javascript 复制代码
new Promise( function(resolve, reject) { /* executor */
    // 执行代码 需要指明resolve与reject的回调位置
});

executor是带有resolvereject两个参数的函数。Promise构造函数执行时立即调用executor函数,resolvereject两个函数作为参数传递给executorresolvereject函数被调用时,分别将promise的状态改为完成fulfilled或失败rejectedexecutor内部通常会执行一些异步操作,一旦异步操作执行完毕,要么调用resolve函数来将promise状态改成fulfilled,要么调用reject函数将promise的状态改为rejected。如果在executor函数中抛出一个错误,那么该promise状态为rejectedexecutor函数的返回值被忽略。

状态

makefile 复制代码
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。

Promise对象只有从pending变为fulfilled和从pending变为rejected的状态改变。只要处于fulfilledrejected,状态就不会再变了。

缺点:无法取消Promise,一旦新建它就会立即执行,无法中途取消;如果不主动catchPromise内部抛出的异常,不会反应到外部,在FireFox中异常不会抛出,在Chrome中的异常抛出但不会触发winodw.onerror事件;当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

实例

Promise可以进行链式调用,避免过多的异步操作造成的回调地狱,then()函数默认会返回一个和原来不同的新的Promise

javascript 复制代码
var promise = new Promise(function(resolve,reject){
     var rand = Math.random() * 2;
     setTimeout(function(){
         if(rand < 1) resolve(rand);
         else reject(rand);
     },1000)
})
promise.then(function(rand){
    console.log("resolve",rand); // resolve回调执行
}).catch(function(rand){
    console.log("reject",rand); // reject回调执行
}).then(function(){
    console.log("再执行then");
    return Promise.resolve(1);
}).then(function(num){
    console.log(num,"还可以继续执行并接收参数");
})

进行多次异步操作,假设只有resolve才会进行下一步异步操作

javascript 复制代码
var promise = new Promise(function(resolve,reject){
     var rand = Math.random() * 2;
     setTimeout(function(){
         if(rand < 1) resolve(rand);
         else reject(rand);
     },1000)
})
promise.then(function(rand){
    console.log("resolve",rand); // resolve回调执行
    return new Promise(function(resolve,reject){
         setTimeout(function(){
             resolve(10000);
         },1000)
     })
}).then(function(num){
    console.log(num);
}).catch(function(rand){
    console.log("reject",rand); // 捕捉reject回调与异常
})

使用catch捕捉异常

javascript 复制代码
var promise = new Promise(function(resolve,reject){
     throw new Error("Error"); // 抛出一个异常
})
promise.then(function(){
    console.log("正常执行");
}).catch(function(err){
    console.log("reject",err); // 捕捉异常
})

then本身可以接受两个参数resolvereject

javascript 复制代码
var promise = new Promise(function(resolve,reject){
     var rand = Math.random() * 2;
     setTimeout(function(){
         if(rand < 1) resolve(rand);
         else reject(rand);
     },1000)
})
promise.then(function(rand){
    console.log("resolve",rand); // resolve回调执行
},function(rand){
    console.log("reject",rand); // reject回调执行
})

方法

Promise.all(iterable)

这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。

javascript 复制代码
var p1 = new Promise((resolve, reject) => {
  resolve("success1");
})

var p2 = new Promise((resolve, reject) => {
  resolve("success2");
})

var p3 = new Promise((resolve, reject) => {
  reject("fail");
})

Promise.all([p1, p2]).then((result) => {
  console.log(result);      // 成功状态 //["success1", "success2"]
}).catch((error) => {
  console.log(error);
})

Promise.all([p1,p3,p2]).then((result) => {
  console.log(result);
}).catch((error) => {
  console.log(error);      // 失败状态 // fail
})

Promise.race(iterable)

iterable参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。

javascript 复制代码
var p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("success");
  },1000);
})

var p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("failed");
  }, 2000);
})

Promise.race([p1, p2]).then((result) => {
  console.log(result); // p1先获得结果,那么就执行p1的回调
}).catch((error) => {
  console.log(error);
})

Promise.resolve(value)

返回一个状态由给定value决定的Promise对象。如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(该value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法。通常而言,如果你不知道一个值是否是Promise对象,使用Promise.resolve(value)来返回一个Promise对象,这样就能将该valuePromise对象形式使用。不要在解析为自身的thenable上调用Promise.resolve,这将导致无限递归,因为它试图展平无限嵌套的promise

javascript 复制代码
// 该值为空或基本类型,直接返回一个fulfilled状态的Promise对象
var promise = Promise.resolve(1);
promise.then((num) => {
    console.log(num); // 1
}).catch((err) => {
    console.log(err);
});

// 如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例
var p1 = Promise.resolve(1);
var p2 = Promise.resolve(p1);
console.log(p1 === p2); // true
p2.then((value) => {
  console.log(value); // 1
});

// 如果该值带有`then`方法的对象),返回的`Promise`对象的最终状态由`then`方法执行决定
var thenable = {then: (resolve, reject) => resolve(1)};
var p1 = Promise.resolve(thenable);
p1.then((value) => {
    console.log(value); // 1
}).catch((err) => {
    console.log(err);
});

Promise.reject(reason)

返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法

javascript 复制代码
var promise = Promise.reject("err");
promise.then(() => {
    console.log(1);
}).catch((err) => {
    console.log(err); // err
});

原型方法

Promise.prototype.then(onFulfilled, onRejected)

添加解决fulfillment和拒绝rejection回调到当前promise,返回一个新的promise,将以回调的返回值来resolve

Promise.prototype.catch(onRejected)

添加一个拒绝rejection回调到当前promise,返回一个新的promise。当这个回调函数被调用,新promise将以它的返回值来resolve,否则如果当前promise进入fulfilled状态,则以当前promise的完成结果作为新promise的完成结果。

Promise.prototype.finally(onFinally)

添加一个事件处理回调于当前promise对象,并且在原promise对象解析完毕后,返回一个新的promise对象。回调会在当前promise运行完毕后被调用,无论当前promise的状态是完成fulfilled还是失败rejected

实现Ajax

javascript 复制代码
function ajax(method, url, data) {
    var request = new XMLHttpRequest();
    return new Promise(function (resolve, reject) {
        request.onreadystatechange = function () {
            if (request.readyState === 4) {
                if (request.status === 200) {
                    resolve(request.responseText);
                } else {
                    reject(request.status);
                }
            }
        };
        request.open(method, url);
        request.send(data);
    });
}
ajax("GET","https://www.baidu.com",[]).then((res) => {
    console.log(res);
}).catch((err) => {
    console.log(err);
})

每日一题

arduino 复制代码
https://github.com/WindrunnerMax/EveryDay

参考

bash 复制代码
https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
相关推荐
mldong5 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排5 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60616 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角7 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!7 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰8 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi9 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen10 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马10 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒11 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端