ES6 - Note5:Promise

1.Promise介绍

Promise最早是社区提出和实现,后面ES6将其写入标准,并原生提供Promise对象,是一种异步编程的解决方案,具体的概念大家可以去查看相关的资料。传统上处理异步都是以callback回调函数的方式完成,但是当回调嵌套的太多,便会使程序很难理解,如下所示

function a(cb){
    console.log(‘a...‘);
    cb(‘a‘);
}
function b(cb){
    console.log(‘b...‘);
    cb(‘b‘);
}
function c(cb){
    console.log(‘c...‘);
    cb(‘c‘);
}
a(() => b( () => c( () => {}) ));
a...
b...
c...

如果后面还有基于C函数的输出结果的逻辑,回调将是很大的困恼。

而使用Promise来处理这种异步回调将会非常的直观,Promise以同步的操作完成异步的处理,如下所示

function a(){
    console.log(‘a...‘);
    return ‘a output‘;
}
function b(res){
    console.log(‘b...‘);
    console.log(‘get A:‘+res);
        return "b output";
}
function c(res){
    console.log(‘c...‘);
    console.log(‘get B:‘+res);
}
new Promise((resolve,reject) => {setTimeout(resolve,1000)}).then(a).then(b).then(c);
Promise { <state>: "pending" }
a...
b...
get A:a output
c...
get B:b output

2.Promise的用法

Promise是一个构造函数,接收一个函数参数,该函数接收两个函数作为参数,分别是resolve,reject。这两个函数由Promise自己提供,无需自己部署。resolve函数将Promise的状态从‘Pending‘转为‘Resolved‘,reject函数将状态从‘Pending‘转为‘rejected‘。

基本语法,如下所示

new Promise((resolve,reject) => {
    if(success){ //异步处理成功
        resolve();
    }else{
        reject();
    }
}).then(onFulfilled,onRejected);

创建一个Promise实例,如下所示

var promise = new Promise((resolve,reject) => {console.log(‘hehe‘);resolve(‘resolved‘)});
promise.then((val) => console.log(val))
console.log(‘current‘);
hehe
current
resolved

resolve函数与reject函数调用时可以传递参数,一般给reject函数传递Error的实例,用于指出抛出的错误,传给reject函数的参数可以是一般的数值,也可以是Promise的实例,这时该Promise的实例状态由参数Promise实例的状态决定,如下所示

var p1 = new Promise((resolve,reject) => {
    setTimeout(()=>{console.log(‘1秒后的 p1‘);resolve(p2);},1000);
});
var p2 = new Promise((resolve,reject)=>{
    setTimeout(()=>{console.log(‘2秒后的 p2‘);resolve(‘p2‘);},2000);
});

p1.then((val)=>console.log(val));
Promise { <state>: "pending" }
1秒后的 p1
2秒后的 p2
p2

如上所示,Promise是创建就立即执行,且then方法的回调函数将在当前脚本所有同步语句执行完执行,但是比定时器的队列优先级要高,如下所示

setTimeout(()=>console.log(‘settimeouting...‘),0);
var promise = new Promise((resolve,reject) => {
    console.log(‘promise constructing...‘);
    reject(new Error(‘error‘));
});
promise.then(null,(reason)=>console.log(reason));
promise constructing...
Promise { <state>: "pending" }
Error: error
堆栈跟踪:
promise<@debugger eval code:4:9
@debugger eval code:2:15

settimeouting...

Promise的原型方法then,该方法为promise实例添加状态改变时的回调函数,第一个参数是状态为resolved时的回调,第二个参数是状态为rejected的回调。如下所示

var p3 = new Promise((resolve,reject) => {
    console.log(‘p3‘);
    resolve(‘p3‘);
});
var p4 = new Promise((resolve,reject) => {
    console.log(‘p4‘);
    setTimeout(()=>resolve(‘p4‘),1500);
});
p3.then(()=>p4).then((result) => console.log(result));//这里需要注意一点,如果then方法返回一个Promise实例,则下一个then回调需要等待该Promise实例的状态改变才会执行。
p3
p4
Promise { <state>: "pending" }
p4

Promise内部抛出的错误不会被捕获(Chrome浏览器除外),除非使用catch方法,如果在resolve之前抛出,则resolve不会执行,相反则相当于没有抛出错误,如下所示

var promise = new Promise((resolve,reject) => {
    console.log(‘promise constructing...‘);
    throw new Error(‘error‘);
    resolve(‘haha‘);
});
promise.then((val)=>console.log(val));
promise constructing...
-------------------------------------------------------------
var promise = new Promise((resolve,reject) => {
    console.log(‘promise constructing...‘);
        resolve(‘haha‘);
    throw new Error(‘error‘);

});
promise.then((val)=>console.log(val));
promise constructing...
haha

使用Promise的原型方法catch捕获错误,该方法其实是.then(null,reject)的别名,如下所示

var promise = new Promise((resolve,reject) => {
    console.log(‘promise constructing...‘);
    throw new Error(‘error‘);
    resolve(‘haha‘);
});
promise.then((val)=>console.log(val)).catch((error)=>console.log(error));

promise constructing...
Promise { <state>: "pending" }
Error: error
堆栈跟踪:
promise<@debugger eval code:3:8
@debugger eval code:1:19

Promise的错误捕获可以使用then方法的第二个参数指定reject的回调函数,也可以使用Promise.prototype.catch方法捕获,但是一般推荐使用方法二,因为catch不仅能捕获到promise内部抛出的错误,then方法中的错误也能被捕获。但是在调用resolve方法之后,再抛出错误,不会被捕获,相当于没有抛出错误,如下所示

var promise = new Promise((resolve,reject) => {
    throw new Error(‘promise error‘);
});
promise.then(null,(err)=>console.log(err));
Promise { <state>: "pending" }
Error: promise error
堆栈跟踪:
promise<@debugger eval code:2:9
@debugger eval code:1:19
---------------------------catch method-------------------
var promise = new Promise((resolve,reject) => {
    reject(new Error(‘promise error‘));
});
promise.catch((error)=>console.log(error));
Promise { <state>: "pending" }
Error: promise error
堆栈跟踪:
promise<@debugger eval code:2:9
@debugger eval code:1:19
---------------------------then方法中报错-------------------
var p5 = new Promise((resolve,reject) => {
    resolve(‘hehe‘);
});
p5.then((val)=>val+x).catch((err)=>console.log(err));
Promise { <state>: "pending" }
ReferenceError: x is not defined
堆栈跟踪:
@debugger eval code:4:16

catch方法也是返回一个Promise,因此在catch后面还可以接着使用链式方法then,但这时then方法报错将不会被前面的catch捕获,如下所示

var p5 = new Promise((resolve,reject) => {
    resolve(‘hehe‘);
});
p5.then((val)=>val+x).catch((err)=>console.log(err)).then((val)=>y+3);
Promise { <state>: "pending" }
ReferenceError: x is not defined
堆栈跟踪:
@debugger eval code:4:16

3.Promise.all

Promise.all方法可以将多个Promise实例[p1,p2,p3...]包装成一个Promise对象A,A的状态由p1,p2,p3...决定:如果p1,p2,p3...的状态都变为onfulfilled,A的状态才变为onfulfilled,且p1,p2,p3...的异步操作结果组成一个数组传给回调函数;但凡p1,p2,p3...中有一个状态变为了rejected,A的状态立即变为rejected,且第一个rejected的返回值会传给回调函数,如下所示

var p1 = new Promise((resolve,reject) => {
    console.log(‘p1...‘);
    setTimeout(()=>resolve(‘p1 resolved...‘),1000);
});
var p2 = new Promise((resolve,reject) => {
    console.log(‘p2...‘);
    setTimeout(()=>resolve(‘p2 resolved...‘),2000);
});
var p3 = new Promise((resolve,reject) => {
    console.log(‘p3...‘);
    setTimeout(()=>resolve(‘p3 resolved...‘),3000);
});

Promise.all([p1,p2,p3]).then((args)=>{console.log(‘3S后的输出:‘);for(let v of args){console.log(v);}});
p1...
p2...
p3...
3S后的输出:
p1 resolved...
p2 resolved...
p3 resolved...
------------------------  有一个Promise实例变为rejected ---------------
var p1 = new Promise((resolve,reject) => {
    console.log(‘p1...‘);
    setTimeout(()=>resolve(‘p1 resolved...‘),1000);
});
var p2 = new Promise((resolve,reject) => {
    console.log(‘p2...‘);
    setTimeout(()=>resolve(‘p2 resolved...‘),2000);
});
var p3 = new Promise((resolve,reject) => {
    console.log(‘p3...‘);
    setTimeout(()=>resolve(‘p3 resolved...‘),3000);
});
var p4 = new Promise((resolve,reject) => {
    console.log(‘p4...‘);
    reject("p4 rejected...");
});
Promise.all([p1,p2,p3,p4]).then((args)=>console.log(args),(reason) => console.log(reason));
p1...
p2...
p3...
p4...
Promise { <state>: "pending" }
p4 rejected...

4.Promise.race

同Promise.all一样,该方法也是将多个Promise实例[p1,p2,p3...]包装成一个新的Promise实例B。"race"的字面意思就是竞争,所以[p1,p2,p3...]谁的状态先改变,B的状态立即改变一样的状态且第一个改变状态的promise实例的返回值传递给回调函数,如下所示

var p1 = new Promise((resolve,reject) => {
    console.log(‘p1...‘);
    setTimeout(()=>resolve(‘p1 resolved...‘),1000);
});
var p2 = new Promise((resolve,reject) => {
    console.log(‘p2...‘);
    setTimeout(()=>resolve(‘p2 resolved...‘),2000);
});
var p3 = new Promise((resolve,reject) => {
    console.log(‘p3...‘);
    setTimeout(()=>resolve(‘p3 resolved...‘),3000);
});

Promise.race([p1,p2,p3]).then((val)=>console.log(val),(reason)=>console.log(reason));

p1...
p2...
p3...
Promise { <state>: "pending" }
p1 resolved...

5.Promise.resolve与Promise.reject

Promise.resolve是将给定的参数转换成一个Promise对象,如下所示

Promise.resolve(arg);//等同于new Promise((resolve)=>resolve(arg))
omise.resolve(‘resolve convert...‘).then((val)=>console.log(val));
Promise { <state>: "pending" }
resolve convert...

根据给定的参数类型不同,Promise.resolve有不同的动作:

A、参数为Promise实例,则直接返回该实例

B、参数为空,执行返回一个resolved状态的新Promise实例

C、参数为普通的数值或对象,则直接返回一个resolved状态的新Promise实例,如下所示

Promise.resolve({x:1}).then((val)=>console.log(val));
Promise { <state>: "pending" }
Object { x: 1 }

D、参数为thenable对象,既对象实现了then方法,此时返回一个新Promise实例并立即执行对象then方法,如下所示

var thenableObj = {
    then(resolve,reject){
        reject(‘test...‘);
    }
};
Promise.resolve(thenableObj).then(null,(reason)=>console.log(reason));

Promise { <state>: "pending" }
test...

Promise.reject与Promise.resolve的用法一致,只是返回的Promise实例的状态为rejected,如下所示

Promise.reject(‘reject convert...‘).then(null,(reason) => console.log(reason));
Promise { <state>: "pending" }
reject convert...

6.给原生Promise对象扩展方法,如下所示

//一下两个函数来自raunyifeng博客
Promise.prototype.done = function (onFulfilled, onRejected) {
  this.then(onFulfilled, onRejected)
    .catch(function (reason) {
      setTimeout(() => { throw reason }, 0);
    });
};
该方法只要执行就可以捕获前面调用链中的错误
Promise.prototype.finally = function (callback) {
  let P = this.constructor;
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason })
  );
};
该方法不管Promise的实例的状态是否改变都会执行回调函数
时间: 2024-08-30 11:24:57

ES6 - Note5:Promise的相关文章

ES6学习笔记五:Promise异步任务

一:Promise对象 Promise对象代表一个异步操作,有三种状态:Pending(进行中).Resolved(已完成,又称 Fulfilled)和Rejected(已失败). 二:创建与使用 var promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } }); Promise构造函数接受一个

ES6中的Promise

Promise作为ES6中最重要的特性之一,我们有必要掌握并理解透彻.本文将由浅到深,讲解Promise的基本概念与使用方法. 1.1ES6 Promise 先拉出来遛遛 复杂的概念先不讲,我们先简单粗暴地把Promise用一下,有个直观感受.那么第一个问题来了,Promise是什么玩意呢?是一个类?对象?数组?函数? 别猜了,直接打印出来看看吧,console.dir(Promise),就这么简单粗暴. 这么一看就明白了,Promise是一个构造函数,自己身上有all.reject.resol

深入理解ES6里的promise

一.ES6 Promise是什么? 复杂的概念先不讲,我们先简单粗暴地把Promise用一下,有个直观感受.那么第一个问题来了,Promise是什么呢?是一个类?对象?数组?函数? 别猜了,直接打印出来看看吧,console.dir(Promise),就这么简单粗暴. 这么一看就明白了,Promise是一个构造函数,自己身上有all.reject.resolve这几个眼熟的方法,原型上有then.catch等同样很眼熟的方法. 这么说用Promise new出来的对象肯定就有then.catch

基础知识:Promise(整理)

基础知识:Promise(整理) (来自牛客网)下面关于promise的说法中,错误的是(D) A. resolve和reject都是直接生成一个进入相应状态的promise对象,其参数就是进入相应状态时传递过去的参数,可以在完成回调的参数中得到 B. Promise.resolve(value),Promise.reject(reason)是Promise构造器上还直接提供了一组静态方法 C. 在调用then方法或者catch方法时都是异步进行的,但是执行速度比较快 D. Promise构造器

es6中的promise对象

Promise是异步里面的一种解决方案,解决了回调嵌套的问题,es6将其进行了语言标准,同意了用法,提供了`promise`对象, promise对象有三种状态:pending(进行中) .Resolved(已经完成)和Rejected(已失败) ES6规定,Promise对象是一个构造函数,用来生成Promise实例. var promise=new Promise(function(resove,reject){ if (/* 异步操作成功 */){ resolve(value); } el

[js高手之路] es6系列教程 - promise常见用法详解(resolve,reject,catch,then,all,race)

关于promise我在之前的文章已经应用过好几次,如[js高手之路]Node.js+jade+express+mongodb+mongoose+promise实现todolist,本文就来讲解下promise的常见用法. 为什么会有promise,他的作用是什么? promise主要是为了解决js中多个异步回调难以维护和控制的问题. 什么是promise? 从图中,我们可以看出,Promise是一个函数,这个函数上有在项目中常用的静态方法:all, race, reject,resolve等,原

Promise 模式解析:Promise模式与异步及声明式编程

一.构建流程 1.(异步)数据源(请求)的构建:Promise的构建并执行请求: 2.处理流程的构建:then将处理函数保存: 二.处理: 1.请求的响应返回: 2.调用后继处理流程. 三. 1.构建源promise的同时发起了异步请求: 2.构建后继处理流程是在一瞬间完成的: 声明式编程语言: 处理流程的构建由程序员负责:声明式: 处理流程的执行由底层解释程序复杂:命令式: https://www.cnblogs.com/feng9exe/p/8950109.html https://www.

自己实现ES6中的Promise API

Promise API是ES6的推荐标准,该API是由各JavaScript的执行引擎在底层,通常是使用C++语言实现的 为了更好地理解Promise API的使用方法并探究其可能的实现方式,笔者在JavaScript层面对Promise API进行了实现. 该实现只是作为实验.学习使用,虽然与内置的实现功能相同,但是在设计和运行效率上肯定是不能相提并论. 我也希望之后能对自己的实现进行改善. 该实现在处理异步任务时,采用了轮询的方式来检测其状态的变化. 具体代码如下(注:笔者采用Node方式进

ES6学习笔记--promise对象

Promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件更合理和更强大.它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象. Promise对象有以下两个特点. (1)对象的状态不受外界影响.Promise对象代表一个异步操作,有三种状态:Pending(进行中).Resolved(已完成,又称 Fulfilled)和Rejected(已失败).只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态.这也是Promi