一 前言
本文主要对ES6的Promise
进行一些入门级的介绍。要想学习一个知识点,肯定是从三个方面出发,what、why、how。下面就跟着我一步步学习吧~
二 什么是Promise
首先是what。那么什么是Promise
呢?
以下是MDN对Promise
的定义
那么什么是异步操作?在学习promise之前需要把这个概念搞明白,下面将抽离一章专门介绍。
2.1 同步与异步
我们知道,JavaScript的执行环境是「单线程」。
所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任务。这个任务可称为主线程。
但实际上还有其他线程,如事件触发线程、ajax请求线程等。
这也就引发了同步和异步的问题。
2.1.1 同步
同步模式,即上述所说的单线程模式,一次只能执行一个任务,函数调用后需等到函数执行结束,返回执行的结果,才能进行下一个任务。如果这个任务执行的时间较长,就会导致「线程阻塞」。
1 /* 例2.1 */ 2 var x = true; 3 while(x); 4 console.log("don't carry out"); //不会执行
上面的例子即同步模式,其中的while是一个死循环,它会阻塞进程,因此第三句console不会执行。
同步模式比较简单,也较容易编写。但问题也显而易见,如果请求的时间较长,而阻塞了后面代码的执行,体验是很不好的。因此对于一些耗时的操作,异步模式则是更好的选择。
2.1.2 异步
下面就来看看异步模式。
异步模式,即与同步模式相反,可以一起执行多个任务,函数调用后不会立即返回执行的结果,如果任务A需要等待,可先执行任务B,等到任务A结果返回后再继续回调。
最常见的异步模式就数定时器了,我们来看看以下的例子。
1 /* 例2.2 */ 2 setTimeout(function() { 3 console.log('taskA, asynchronous'); 4 }, 0); 5 console.log('taskB, synchronize'); 6 //while(true); 7 8 -------ouput------- 9 taskB, synchronize 10 taskA, asynchronous
我们可以看到,定时器延时的时间明明为0,但taskA还是晚于taskB执行。这是为什么呢?由于定时器是异步的,异步任务会在当前脚本的所有同步任务执行完才会执行。如果同步代码中含有死循环,即将上例的注释去掉,那么这个异步任务就不会执行,因为同步任务阻塞了进程。
2.1.3 回调函数
提起异步,就不得不谈谈回调函数了。上例中,setTimeout
里的function
便是回调函数。可以简单理解为:(执行完)回(来)调(用)的函数。
以下是WikiPedia对于callback
的定义。
可以看出,回调函数是一段可执行的代码段,它以「参数」的形式传递给其他代码,在其合适的时间执行这段(回调函数)的代码。
WikiPedia同时提到
也就是说,回调函数不仅可以用于异步调用,一般同步的场景也可以用回调。在同步调用下,回调函数一般是最后执行的。而异步调用下,可能一段时间后执行或不执行(未达到执行的条件)。
1 /* 例2.3 */ 2 /******************同步回调******************/ 3 var fun1 = function(callback) { 4 //do something 5 console.log("before callback"); 6 (callback && typeof(callback) === 'function') && callback(); 7 console.log("after callback"); 8 } 9 var fun2 = function(param) { 10 //do something 11 var start = new Date(); 12 while((new Date() - start) < 3000) { //delay 3s 13 } 14 console.log("I'm callback"); 15 } 16 fun1(fun2); 17 18 -------output-------- 19 before callback 20 //after 3s 21 I’m callback 22 after callback
由于是同步回调,会阻塞后面的代码,如果fun2是个死循环,后面的代码就不执行了。
上一小节中setTimeout
就是常见的异步回调,另外常见的异步回调即ajax请求。
1 /* 例2.4 */ 2 /******************异步回调******************/ 3 function request(url, param, successFun, errorFun) { 4 $.ajax({ 5 type: 'GET', 6 url: url, 7 param: param, 8 async: true, //默认为true,即异步请求;false为同步请求 9 success: successFun, 10 error: errorFun 11 }); 12 } 13 request('test.html', '', function(data) { 14 //请求成功后的回调函数,通常是对请求回来的数据进行处理 15 console.log('请求成功啦, 这是返回的数据:', data); 16 },function(error) { 17 console.log('sorry, 请求失败了, 这是失败信息:', error); 18 });
2.2 为什么使用Promise
说完了以上基本概念,我们就可以继续学习Promise
了。
上面提到,Promise
对象是用于异步操作的。既然我们可以使用异步回调来进行异步操作,为什么还要引入一个Promise
新概念,还要花时间学习它呢?不要着急,下面就来谈谈Promise
的过人之处。
我们先看看下面的demo,利用Promise
改写例2.4的异步回调。
1 /* 例2.5 */ 2 function sendRequest(url, param) { 3 return new Promise(function (resolve, reject) { 4 request(url, param, resolve, reject); 5 }); 6 } 7 8 sendRequest('test.html', '').then(function(data) { 9 //异步操作成功后的回调 10 console.log('请求成功啦, 这是返回的数据:', data); 11 }, function(error) { 12 //异步操作失败后的回调 13 console.log('sorry, 请求失败了, 这是失败信息:', error); 14 });
这么一看,并没有什么区别,还比上面的异步回调复杂,得先新建Promise再定义其回调。其实,Promise
的真正强大之处在于它的多重链式调用,可以避免层层嵌套回调。如果我们在第一次ajax请求后,还要用它返回的结果再次请求呢?
1 /* 例2.6 */ 2 request('test1.html', '', function(data1) { 3 console.log('第一次请求成功, 这是返回的数据:', data1); 4 request('test2.html', data1, function (data2) { 5 console.log('第二次请求成功, 这是返回的数据:', data2); 6 request('test3.html', data2, function (data3) { 7 console.log('第三次请求成功, 这是返回的数据:', data3); 8 //request... 继续请求 9 }, function(error3) { 10 console.log('第三次请求失败, 这是失败信息:', error3); 11 }); 12 }, function(error2) { 13 console.log('第二次请求失败, 这是失败信息:', error2); 14 }); 15 }, function(error1) { 16 console.log('第一次请求失败, 这是失败信息:', error1); 17 });
以上出现了多层回调嵌套,有种晕头转向的感觉。这也就是我们常说的厄运回调金字塔(Pyramid of Doom),编程体验十分不好。而使用Promise
,我们就可以利用then
进行「链式回调」,将异步操作以同步操作的流程表示出来。
1 /* 例2.7 */ 2 sendRequest('test1.html', '').then(function(data1) { 3 console.log('第一次请求成功, 这是返回的数据:', data1); 4 }).then(function(data2) { 5 console.log('第二次请求成功, 这是返回的数据:', data2); 6 }).then(function(data3) { 7 console.log('第三次请求成功, 这是返回的数据:', data3); 8 }).catch(function(error) { 9 //用catch捕捉前面的错误 10 console.log('sorry, 请求失败了, 这是失败信息:', error); 11 });
是不是明显清晰很多?孰优孰略也无需多说了吧~下面就让我们真正进入Promise
的学习。
三 Promise的基本用法
3.1 基本用法
上一小节我们认识了promise
长什么样,但对它用到的resolve
、reject
、then
、catch
想必还不理解。下面我们一步步学习。
Promise
对象代表一个未完成、但预计将来会完成的操作。
它有以下三种状态:
pending
:初始值,不是fulfilled,也不是rejectedfulfilled
:代表操作成功rejected
:代表操作失败
Promise
有两种状态改变的方式,既可以从pending
转变为fulfilled
,也可以从pending
转变为rejected
。一旦状态改变,就「凝固」了,会一直保持这个状态,不会再发生变化。当状态发生变化,promise.then
绑定的函数就会被调用。
注意:Promise
一旦新建就会「立即执行」,无法取消。这也是它的缺点之一。
下面就通过例子进一步讲解。
1 /* 例3.1 */ 2 //构建Promise 3 var promise = new Promise(function (resolve, reject) { 4 if (/* 异步操作成功 */) { 5 resolve(data); 6 } else { 7 /* 异步操作失败 */ 8 reject(error); 9 } 10 });
类似构建对象,我们使用new
来构建一个Promise
。Promise
接受一个「函数」作为参数,该函数的两个参数分别是resolve
和reject
。这两个函数就是就是「回调函数」,由JavaScript引擎提供。
resolve
函数的作用:在异步操作成功时调用,并将异步操作的结果,作为参数传递出去; reject
函数的作用:在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成以后,可以用then
方法指定resolved
状态和reject
状态的回调函数。
1 /* 接例3.1 */ 2 promise.then(onFulfilled, onRejected); 3 4 promise.then(function(data) { 5 // do something when success 6 }, function(error) { 7 // do something when failure 8 });
then
方法会返回一个Promise。它有两个参数,分别为Promise从pending
变为fulfilled
和rejected
时的回调函数(第二个参数非必选)。这两个函数都接受Promise对象传出的值作为参数。
简单来说,then
就是定义resolve
和reject
函数的,其resolve
参数相当于:
1 function resolveFun(data) { 2 //data为promise传出的值 3 }
而新建Promise中的'resolve(data)',则相当于执行resolveFun函数。
Promise新建后就会立即执行。而then
方法中指定的回调函数,将在当前脚本所有同步任务执行完才会执行。如下例:
1 /* 例3.2 */ 2 var promise = new Promise(function(resolve, reject) { 3 console.log('before resolved'); 4 resolve(); 5 console.log('after resolved'); 6 }); 7 8 promise.then(function() { 9 console.log('resolved'); 10 }); 11 12 console.log('outer'); 13 14 -------output------- 15 before resolved 16 after resolved 17 outer 18 resolved
由于resolve
指定的是异步操作成功后的回调函数,它需要等所有同步代码执行后才会执行,因此最后打印'resolved',这个和例2.2是一样的道理。
3.2 基本API
.then()
语法:Promise.prototype.then(onFulfilled, onRejected)
对promise添加onFulfilled
和onRejected
回调,并返回的是一个新的Promise实例(不是原来那个Promise实例),且返回值将作为参数传入这个新Promise的resolve
函数。
因此,我们可以使用链式写法,如上文的例2.7。由于前一个回调函数,返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
.catch()
语法:Promise.prototype.catch(onRejected)
该方法是.then(undefined, onRejected)
的别名,用于指定发生错误时的回调函数。
1 /* 例3.3 */ 2 promise.then(function(data) { 3 console.log('success'); 4 }).catch(function(error) { 5 console.log('error', error); 6 }); 7 8 /*******等同于*******/ 9 promise.then(function(data) { 10 console.log('success'); 11 }).then(undefined, function(error) { 12 console.log('error', error); 13 });
1 /* 例3.4 */ 2 var promise = new Promise(function (resolve, reject) { 3 throw new Error('test'); 4 }); 5 /*******等同于*******/ 6 var promise = new Promise(function (resolve, reject) { 7 reject(new Error('test')); 8 }); 9 10 //用catch捕获 11 promise.catch(function (error) { 12 console.log(error); 13 }); 14 -------output------- 15 Error: test
从上例可以看出,reject
方法的作用,等同于抛错。
promise对象的错误,会一直向后传递,直到被捕获。即错误总会被下一个catch
所捕获。then
方法指定的回调函数,若抛出错误,也会被下一个catch
捕获。catch
中也能抛错,则需要后面的catch
来捕获。
1 /* 例3.5 */ 2 sendRequest('test.html').then(function(data1) { 3 //do something 4 }).then(function (data2) { 5 //do something 6 }).catch(function (error) { 7 //处理前面三个Promise产生的错误 8 });
上文提到过,promise状态一旦改变就会凝固,不会再改变。因此promise一旦fulfilled
了,再抛错,也不会变为rejected
,就不会被catch
了。
1 /* 例3.6 */ 2 var promise = new Promise(function(resolve, reject) { 3 resolve(); 4 throw 'error'; 5 }); 6 7 promise.catch(function(e) { 8 console.log(e); //This is never called 9 });
如果没有使用catch
方法指定处理错误的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应(Chrome会抛错),这是Promise的另一个缺点。
1 /* 例3.7 */ 2 var promise = new Promise(function (resolve, reject) { 3 resolve(x); 4 }); 5 promise.then(function (data) { 6 console.log(data); 7 });
如图所示,只有Chrome会抛错,且promise状态变为rejected
,Firefox和Safari中错误不会被捕获,也不会传递到外层代码,最后没有任何输出,promise状态也变为rejected
。
.all()
语法:Promise.all(iterable)
该方法用于将多个Promise实例,包装成一个新的Promise实例。
var p = Promise.all([p1, p2, p3]);
Promise.all
方法接受一个数组(或具有Iterator接口)作参数,数组中的对象(p1、p2、p3)均为promise实例(如果不是一个promise,该项会被用Promise.resolve
转换为一个promise)。它的状态由这三个promise实例决定。
- 当p1, p2, p3状态都变为
fulfilled
,p的状态才会变为fulfilled
,并将三个promise返回的结果,按参数的顺序(而不是resolved
的顺序)存入数组,传给p的回调函数,如例3.8。 - 当p1, p2, p3其中之一状态变为
rejected
,p的状态也会变为rejected
,并把第一个被reject
的promise的返回值,传给p的回调函数,如例3.9。
1 /* 例3.8 */ 2 var p1 = new Promise(function (resolve, reject) { 3 setTimeout(resolve, 3000, "first"); 4 }); 5 var p2 = new Promise(function (resolve, reject) { 6 resolve('second'); 7 }); 8 var p3 = new Promise((resolve, reject) => { 9 setTimeout(resolve, 1000, "third"); 10 }); 11 12 Promise.all([p1, p2, p3]).then(function(values) { 13 console.log(values); 14 }); 15 16 -------output------- 17 //约 3s 后 18 ["first", "second", "third"]
1 /* 例3.9 */ 2 var p1 = new Promise((resolve, reject) => { 3 setTimeout(resolve, 1000, "one"); 4 }); 5 var p2 = new Promise((resolve, reject) => { 6 setTimeout(reject, 2000, "two"); 7 }); 8 var p3 = new Promise((resolve, reject) => { 9 reject("three"); 10 }); 11 12 Promise.all([p1, p2, p3]).then(function (value) { 13 console.log('resolve', value); 14 }, function (error) { 15 console.log('reject', error); // => reject three 16 }); 17 18 -------output------- 19 reject three
这多个 promise 是同时开始、并行执行的,而不是顺序执行。从下面例子可以看出。如果一个个执行,那至少需要 1+32+64+128
1 /* 例3.10 */ 2 function timerPromisefy(delay) { 3 return new Promise(function (resolve) { 4 setTimeout(function () { 5 resolve(delay); 6 }, delay); 7 }); 8 } 9 var startDate = Date.now(); 10 11 Promise.all([ 12 timerPromisefy(1), 13 timerPromisefy(32), 14 timerPromisefy(64), 15 timerPromisefy(128) 16 ]).then(function (values) { 17 console.log(Date.now() - startDate + 'ms'); 18 console.log(values); 19 }); 20 -------output------- 21 133ms //不一定,但大于128ms 22 [1,32,64,128]
.race()
语法:Promise.race(iterable)
该方法同样是将多个Promise实例,包装成一个新的Promise实例。
var p = Promise.race([p1, p2, p3]);
Promise.race
方法同样接受一个数组(或具有Iterator接口)作参数。当p1, p2, p3中有一个实例的状态发生改变(变为fulfilled
或rejected
),p的状态就跟着改变。并把第一个改变状态的promise的返回值,传给p的回调函数。
1 /* 例3.11 */ 2 var p1 = new Promise(function(resolve, reject) { 3 setTimeout(reject, 500, "one"); 4 }); 5 var p2 = new Promise(function(resolve, reject) { 6 setTimeout(resolve, 100, "two"); 7 }); 8 9 Promise.race([p1, p2]).then(function(value) { 10 console.log('resolve', value); 11 }, function(error) { 12 //not called 13 console.log('reject', error); 14 }); 15 -------output------- 16 resolve two 17 18 var p3 = new Promise(function(resolve, reject) { 19 setTimeout(resolve, 500, "three"); 20 }); 21 var p4 = new Promise(function(resolve, reject) { 22 setTimeout(reject, 100, "four"); 23 }); 24 25 Promise.race([p3, p4]).then(function(value) { 26 //not called 27 console.log('resolve', value); 28 }, function(error) { 29 console.log('reject', error); 30 }); 31 -------output------- 32 reject four
在第一个promise对象变为resolve后,并不会取消其他promise对象的执行,如下例
1 /* 例3.12 */ 2 var fastPromise = new Promise(function (resolve) { 3 setTimeout(function () { 4 console.log('fastPromise'); 5 resolve('resolve fastPromise'); 6 }, 100); 7 }); 8 var slowPromise = new Promise(function (resolve) { 9 setTimeout(function () { 10 console.log('slowPromise'); 11 resolve('resolve slowPromise'); 12 }, 1000); 13 }); 14 // 第一个promise变为resolve后程序停止 15 Promise.race([fastPromise, slowPromise]).then(function (value) { 16 console.log(value); // => resolve fastPromise 17 }); 18 -------output------- 19 fastPromise 20 resolve fastPromise 21 slowPromise //仍会执行
.resolve()
语法:
Promise.resolve(value);
Promise.resolve(promise);
Promise.resolve(thenable);
它可以看做new Promise()
的快捷方式。
1 Promise.resolve('Success'); 2 3 /*******等同于*******/ 4 new Promise(function (resolve) { 5 resolve('Success'); 6 });
这段代码会让这个Promise对象立即进入resolved
状态,并将结果success
传递给then
指定的onFulfilled
回调函数。由于Promise.resolve()
也是返回Promise对象,因此可以用.then()
处理其返回值。
/* 例3.13 */ Promise.resolve('success').then(function (value) { console.log(value); }); -------output------- Success
/* 例3.14 */ //Resolving an array Promise.resolve([1,2,3]).then(function(value) { console.log(value[0]); // => 1 }); //Resolving a Promise var p1 = Promise.resolve('this is p1'); var p2 = Promise.resolve(p1); p2.then(function (value) { console.log(value); // => this is p1 });
Promise.resolve()
的另一个作用就是将thenable
对象(即带有then
方法的对象)转换为promise对象。
1 /* 例3.15 */ 2 var p1 = Promise.resolve({ 3 then: function (resolve, reject) { 4 resolve("this is an thenable object!"); 5 } 6 }); 7 console.log(p1 instanceof Promise); // => true 8 9 p1.then(function(value) { 10 console.log(value); // => this is an thenable object! 11 }, function(e) { 12 //not called 13 });
再看下面两个例子,无论是在什么时候抛异常,只要promise状态变成resolved
或rejected
,状态不会再改变,这和新建promise是一样的。
1 /* 例3.16 */ 2 //在回调函数前抛异常 3 var p1 = { 4 then: function(resolve) { 5 throw new Error("error"); 6 resolve("Resolved"); 7 } 8 }; 9 10 var p2 = Promise.resolve(p1); 11 p2.then(function(value) { 12 //not called 13 }, function(error) { 14 console.log(error); // => Error: error 15 }); 16 17 //在回调函数后抛异常 18 var p3 = { 19 then: function(resolve) { 20 resolve("Resolved"); 21 throw new Error("error"); 22 } 23 }; 24 25 var p4 = Promise.resolve(p3); 26 p4.then(function(value) { 27 console.log(value); // => Resolved 28 }, function(error) { 29 //not called 30 });
.reject()
语法:Promise.reject(reason)
这个方法和上述的Promise.resolve()
类似,它也是new Promise()
的快捷方式。
1 Promise.reject(new Error('error')); 2 3 /*******等同于*******/ 4 new Promise(function (resolve, reject) { 5 reject(new Error('error')); 6 });
这段代码会让这个Promise对象立即进入rejected
状态,并将错误对象传递给then
指定的onRejected
回调函数。
四 Promise常见问题
经过上一章的学习,相信大家已经学会使用Promise
。
总结一下创建promise的流程:
- 使用
new Promise(fn)
或者它的快捷方式Promise.resolve()
、Promise.reject()
,返回一个promise对象 - 在
fn
中指定异步的处理
处理结果正常,调用resolve
处理结果错误,调用reject
如果使用ES6的箭头函数,将会使写法更加简单清晰。
这一章节,将会用例子的形式,以说明promise使用过程中的注意点及容易犯的错误。
情景1:reject 和 catch 的区别
- promise.then(onFulfilled, onRejected)
在onFulfilled
中发生异常的话,在onRejected
中是捕获不到这个异常的。 - promise.then(onFulfilled).catch(onRejected)
.then
中产生的异常能在.catch
中捕获
一般情况,还是建议使用第二种,因为能捕获之前的所有异常。当然了,第二种的.catch()
也可以使用.then()
表示,它们本质上是没有区别的,.catch === .then(null, onRejected)
情景2:如果在then中抛错,而没有对错误进行处理(即catch),那么会一直保持reject状态,直到catch了错误
1 /* 例4.1 */ 2 function taskA() { 3 console.log(x); 4 console.log("Task A"); 5 } 6 function taskB() { 7 console.log("Task B"); 8 } 9 function onRejected(error) { 10 console.log("Catch Error: A or B", error); 11 } 12 function finalTask() { 13 console.log("Final Task"); 14 } 15 var promise = Promise.resolve(); 16 promise 17 .then(taskA) 18 .then(taskB) 19 .catch(onRejected) 20 .then(finalTask); 21 22 -------output------- 23 Catch Error: A or B,ReferenceError: x is not defined 24 Final Task
根据例4.1的输出结果及流程图,可以看出,A抛错时,会按照 taskA → onRejected → finalTask这个流程来处理。A抛错后,若没有对它进行处理,如例3.7,状态就会维持rejected
,taskB不会执行,直到catch
了错误。
1 /* 例4.2 */ 2 function taskA() { 3 console.log(x); 4 console.log("Task A"); 5 } 6 function taskB() { 7 console.log("Task B"); 8 } 9 function onRejectedA(error) { 10 console.log("Catch Error: A", error); 11 } 12 function onRejectedB(error) { 13 console.log("Catch Error: B", error); 14 } 15 function finalTask() { 16 console.log("Final Task"); 17 } 18 var promise = Promise.resolve(); 19 promise 20 .then(taskA) 21 .catch(onRejectedA) 22 .then(taskB) 23 .catch(onRejectedB) 24 .then(finalTask); 25 26 -------output------- 27 Catch Error: A ReferenceError: x is not defined 28 Task B 29 Final Task
将例4.2与4.1对比,在taskA后多了对A的处理,因此,A抛错时,会按照A会按照 taskA → onRejectedA → taskB → finalTask这个流程来处理,此时taskB是正常执行的。
情景3:每次调用then
都会返回一个新创建的promise对象,而then
内部只是返回的数据
1 /* 例4.3 */ 2 //方法1:对同一个promise对象同时调用 then 方法 3 var p1 = new Promise(function (resolve) { 4 resolve(100); 5 }); 6 p1.then(function (value) { 7 return value * 2; 8 }); 9 p1.then(function (value) { 10 return value * 2; 11 }); 12 p1.then(function (value) { 13 console.log("finally: " + value); 14 }); 15 -------output------- 16 finally: 100 17 18 //方法2:对 then 进行 promise chain 方式进行调用 19 var p2 = new Promise(function (resolve) { 20 resolve(100); 21 }); 22 p2.then(function (value) { 23 return value * 2; 24 }).then(function (value) { 25 return value * 2; 26 }).then(function (value) { 27 console.log("finally: " + value); 28 }); 29 -------output------- 30 finally: 400
第一种方法中,then
的调用几乎是同时开始执行的,且传给每个then的value都是100,这种方法应当避免。方法二才是正确的链式调用。
因此容易出现下面的错误写法:
1 /* 例4.4 */ 2 function badAsyncCall(data) { 3 var promise = Promise.resolve(data); 4 promise.then(function(value) { 5 //do something 6 return value + 1; 7 }); 8 return promise; 9 } 10 badAsyncCall(10).then(function(value) { 11 console.log(value); //想要得到11,实际输出10 12 }); 13 -------output------- 14 10
正确的写法应该是:
1 /* 改写例4.4 */ 2 function goodAsyncCall(data) { 3 var promise = Promise.resolve(data); 4 return promise.then(function(value) { 5 //do something 6 return value + 1; 7 }); 8 } 9 goodAsyncCall(10).then(function(value) { 10 console.log(value); 11 }); 12 -------output------- 13 11
情景4:在异步回调中抛错,不会被catch
到
1 // Errors thrown inside asynchronous functions will act like uncaught errors 2 var promise = new Promise(function(resolve, reject) { 3 setTimeout(function() { 4 throw 'Uncaught Exception!'; 5 }, 1000); 6 }); 7 8 promise.catch(function(e) { 9 console.log(e); //This is never called 10 });
情景5: promise状态变为resove
或reject
,就凝固了,不会再改变
console.log(1); new Promise(function (resolve, reject){ reject(); setTimeout(function (){ resolve(); //not called }, 0); }).then(function(){ console.log(2); }, function(){ console.log(3); }); console.log(4); -------output------- 1 4 3
五 结语
关于promise
就先介绍到这边了,比较基础,有不足的地方欢迎指出,有更好的也欢迎补充~