编后吐槽:写的快花眼,很详细,耐心看必受益匪浅
JavaScript的执行环境是「单线程」的。所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任务。这个任务可称为主线程。但实际上还有其他线程,如事件触发线程、ajax请求线程等。因为javascript的单线程原理,使得网络操作,浏览器事件,都必须是异步执行的。
* 同步与异步
- 同步:同步模式,即上述所说的单线程模式,一次只能执行一个任务,函数调用后需等到函数执行结束,返回执行的结果,才能进行下一个任务。如果这个任务执行的时间较长,就会导致「线程阻塞」。
var x = true;
while(x);
console.log("don‘t’ carry out");
// javascript 单线程原理导致同步执行,第三步不被执行
- 异步:可以一起执行多个任务,函数调用后不会立即返回执行的结果,如果任务A需要等待,可先执行任务B,等到任务A结果返回后再继续回调。
// 常见异步,定时器的使用
setTimeout(function() {
console.log('taskA, run as asynchronous');
}, 0)
console.log('taskB, run as synchronize');
//while(true);
// taskB, run as synchronize
// taskA, run as asynchronous
即使延时时长为0,taskA依旧晚于taskB;因为定时器是异步的,异步任务会在当前脚本所有同步任务完成之后才被执行。,如果同步任务中含有阻塞任务,即放开代码中的while(true)
,那么taskA将不会被执行。
* 什么是Promise
古人云:“君子一诺千金”,这种“承诺某个状态将来会执行,并且该状态不会被改变”的对象在JavaScript
中称为Promise
对象,他是一个构造函数,能将异步的操作以同步的形式表达出来,避免了嵌套地狱(层层嵌套)的发生。它供了统一的API,使得控制异步更加容易
* 回调函数
回调函数是一段可执行的代码段,它以「参数」的形式传递给其他代码,在其合适的时间执行这段(回调函数)的代码。
异步可以回调,同步也可以回调;
// 同步回调
var func1 = function(cb) {
// ..do something
console.log("before callback");
(cb && typeof(cb) === 'function') && cb();
console.log("after callback");
}
var func2 = function(param) {
// ..do something
var start = new Date();
if(( new Date() - start) < 3000 ){ } // 同步实现延时函数
console.log("I am callback");
}
func1(func2);
------output-------
// before callback
(after 3s...)
// I am callback
// after callback
由于是同步回调,会阻塞后面的代码,如果func2是个死循环,后面的代码就不执行了。为解决这个问题,我们使用异步回调,除了常见的setTimeout
,ajax
也是应用方式之一
// 异步回调
function request(url, param, successFun, errorFunc) {
$.ajax({
type: 'GET',
url: url,
param: param,
async: true, // 默认为true,如果设置为false则变成同步请求
success: successFunc,
error: errorFunc
});
}
request('test.html', '', function(data) {
// 第三个参数为返回成功时执行的函数
console.log('cbData: ', data);
}, function(data) {
// 第四个参数为失败时的函数
console.log('error: ', error);
});
* 为什么要用Promise
既然已经可以实现异步回调,那我们为什么还要用Promise呢?
javascript代码
function callback () {
console.log("Done");
}
console.log("before setTimeout()")
setTimeout(callback, 1000);
console.log("after setTimeout()");
控制台输出
before setTimeout()
after setTimeout()
(等待一秒后...)
Done
说明: setTimeout()
延时函数时javascript实现异步执行的手段之一,该例中它将callback
放到等待队列,并且开始为延时量计时,当到达延时量主线程中的事件还没执行完成,那等待队列中的事件继续保持等待,直到主线程的执行完成才被加入到线程中执行。所以代码中说的”等待一秒后”其实并不准确。
可见,异步操作会在将来的某个时间点触发一个函数调用。
如果我们有这样一个需求:下一个请求或函数必须要有上一步返回的数据才能执行,如下:
request('test1.html', '', function(data1) {
console.log('第一次请求成功, 这是返回的数据:', data1);
request('test2.html', data1, function (data2) {
console.log('第二次请求成功, 这是返回的数据:', data2);
request('test3.html', data2, function (data3) {
console.log('第三次请求成功, 这是返回的数据:', data3);
//request... 继续请求
}, function(error3) {
console.log('第三次请求失败, 这是失败信息:', error3);
});
}, function(error2) {
console.log('第二次请求失败, 这是失败信息:', error2);
});
}, function(error1) {
console.log('第一次请求失败, 这是失败信息:', error1);
});
以上出现了多层回调嵌套,有种晕头转向的感觉。这也就是我们常说的厄运回调金字塔(Pyramid of Doom),编程体验十分不好
不仅如此,这种代码结构,可读性和可维护性太差,代码复用率也很低,我们希望能将数据请求和数据处理区分开来,Promise就可以利用then进行「链式回调」,将异步操作以同步操作的流程表示出来。
sendRequest('test1.html', '').then(function(data1) {
console.log('第一次请求成功, 这是返回的数据:', data1);
}).then(function(data2) {
console.log('第二次请求成功, 这是返回的数据:', data2);
}).then(function(data3) {
console.log('第三次请求成功, 这是返回的数据:', data3);
}).catch(function(error) {
//用catch捕捉前面的错误
console.log('sorry, 请求失败了, 这是失败信息:', error);
});
Promise不仅能以同步的方式表示异步操作,还能catch
到异常,这是ajax
无法实现的
* Promise in JS
1. 基本结构
ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。
javascript代码
var pm = new Promise(function(resolve, reject) {
// ..some code
if( /*异步操作结果*/) {
resolve(value);
} else {
reject(error);
}
})
pm.then(function(){
// handle resolveFunc
},function() {
// handle rejectFunc
})
这就是它的基本模型,为了继续往下学习,我们需要补充一下Promise的一些基础知识。
2. Promise 三种状态
Promise链式调用用到resolve
,reject
,then
,catch
,他有以下三种状态
- pending - 进行中,或者等待中,表示还没有得到结果
- fulfilled - 已成功,在异步操作成功时调用,并将结果作为参数传递出去。
- rejected - 已失败。在异步操作失败时调用,并将报出的错误作为参数传递出去。
只有异步操作的结果可以决定当前是哪种状态,其他任何操作都无法改变这个状态,这也是Promise名字的由来。所谓的“君子一言,驷马难追”,承诺将来某个状态,且该状态不会被其他因素改变。
注释: 从基本用法的例子中我们看到Promise构造函数的参数是
resolve
和reject
,并不是三种状态中的fulfilled
和rejected
,原因就是:resolved
表示的是已结束(已定型),它包含fullfilled
和rejected
两种状态,但使用中,我们默认的将resolved
当做fulfilled
(成功)使用。
3. Promise 对象的特点
(1)对象的状态不受外界因素影响。以上已经说过。
(2)一旦结果状态生成,就不会在改变,任何时候都可以得到这个结果。Promise
对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种状态发生了,状态就凝固不变,并一直保持这个结果。就算改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这和事件监听有很大的区别,事件监听是实时的,如果错过了监听时机,就得不到要监听的结果了
promise也有缺点
- 无法取消Promise,一旦新建它就会立即执行,无法中途取消
- 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部(所以健壮的代码要catch错误)
- 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
* 基本API
1 .then()
语法:
Promise.prototype.then( onFulfilled, onRejected )
这是Promise最常用也是最重要的一个API,他定义了Promise的两个回调函数,并返回一个新的Promise实例,且返回值传入这个行Promise的resolve
函数中。
因此,我们可以使用链式写法,如为什么要用Promise中的最后一例,返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
2. .catch() - 抛出异常
语法:
Promise.prototype.catch( onRejected )
该方法是.then(undefined, onRejected)
的别名,用于指定发生错误时的回调函数。
var promise = new Promise(function(resolve, reject)){
// some code
}
promise.then(function(data) {
console.log('success');
}, function(error) {
conosle.log('error', error)
})
/*---等价于---*/
promise.then(function(data){
console.log('success');
}).catch(function(error) {
consol;e.log('error', error)
})
再看一例
var promise = new Promise(function(resoleve, reject) {
throw new Error('test');
});
// 等同于
var promise = new Promise(resovle, reject) {
reject(new Error('test'));
}
// 以上的reject我们用catch来捕获
promise.catch(function (error) {
console.log(error);
});
---output---
Error: test
从上例可以看出,reject
方法的作用,等同于抛错,这是Promise另一大优势
关于Promise抛错有几下几个需要注意的地方
- Promise对象的错误,会一直向后传递,知道被捕获,即错误总会被下一个catch所捕获。then方法指定的回调函数,若抛出错误,也会被下一个catch捕获。catch中也能抛错,则需要后面的catch来捕获。
sendRequest('test.html').then(function(data1) {
//do something
}).then(function (data2) {
//do something
}).catch(function (error) {
//处理前面三个Promise产生的错误
});
- promise状态一旦改变就会凝固,不会再改变。因此promise一旦fulfilled了,再抛错,也不会变为rejected,就不会被catch了。
var promise = new Promise(function(resolve, reject) {
resolve();
throw 'error';
});
promise.catch(function(e) {
console.log(e); //This is never called
});
- 如果没有使用catch方法指定处理错误的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应(Chrome会抛错),这是Promise的另一个缺点。
var promise = new Promise(function(resolve, reject) {
resolve(); // 状态已经被返回为resolve
throw 'error';
});
promise.catch(function(e) {
console.log(e); //This is never called
});
抛错实例:
var p = new Promise(function(resolve, reject) {
resolve(x);
});
p.then(function(data){
console.log(data);
});
Chrome上的表现;
据说只有chrome会报错,其他浏览器的错误不会被捕获,也不会传递到外层代码,最后没有任何输出,promise的状态也变为rejected
3 .all() - Promise中的“逻辑与”
全部执行结束且状态均为resolve
才为resolve
,有一个执行错误,则为reject
语法:
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的回调函数
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 3000, "first");
});
var p2 = new Promise(function(resolve, reject) {
resolve("second");
});
var p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1000, "third");
});
Promise.all([p1, p2, p3]).then(function(values) {
console.log(values);
});
// ----output----
// 约3秒后
// ["first", "second", "third"]
- 当p1, p2, p3其中之一状态变为rejected,p的状态也会变为rejected,并把第一个被reject的promise的返回值,立即触发并传给p的回调函数
// 将上例中的p2适当修改如下
var p2 = new Promise(function(resolve, reject) {
resolve(x);
});
这时,p2会抛出错误,立即传给Promise.all()
,结束执行。
- 这多个 promise 是同时开始、并行执行的,而不是顺序执行
4 .race() - 竞速执行
需要注意的是,它并不是Promise中的“逻辑或”,而是将先结束的传值给 then
,最先执行完成的是resolve
即resolve
,为reject
则reject
语法:
Promise.race( iterable )
该方法同样是将多个Promise实例,包装成一个新的Promise实例。
var p = Promise.race([p1, p2, p3]);
-
Promise.race
方法同样接受一个数组(或具有Iterator接口)作参数。当p1, p2, p3中有一个实例的状态发生改变(变为fulfilled或rejected),p的状态就跟着改变。并把第一个改变状态的promise的返回值,传给p的回调函数。
执行resolve
var p1 = new Promise(function(resolve, reject) {
setTimeout(reject, 500, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "two");
});
Promise.race([p1, p2]).then(function(value) {
console.log('resolve', value);
}, function(error) {
//not called
console.log('reject', error);
});
-------output-------
resolve two
执行reject
var p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "three");
});
var p4 = new Promise(function(resolve, reject) {
setTimeout(reject, 100, "four");
});
Promise.race([p3, p4]).then(function(value) {
//not called
console.log('resolve', value);
}, function(error) {
console.log('reject', error);
});
-------output-------
reject four
- 在第一个promise对象变为resolve后,并不会取消其他promise对象的执行,如下例
var fastPromise = new Promise(function (resolve) {
setTimeout(function () {
console.log('fastPromise');
resolve('resolve fastPromise');
}, 100);
});
var slowPromise = new Promise(function (resolve) {
setTimeout(function () {
console.log('slowPromise');
resolve('resolve slowPromise');
}, 1000);
});
// 第一个promise变为resolve后程序停止
Promise.race([fastPromise, slowPromise]).then(function (value) {
console.log(value); // => resolve fastPromise
});
-------output-------
fastPromise
resolve fastPromise
slowPromise //仍会执行
5 .resolve() - 立即执行Promise-resolve
语法: 1. Promise.resolve(value); 2. Promise.resolve(promise); 3. Promise.resolve(thenable);
它可以看做new Promise()的快捷方式。
new Promise(function (resolve) {
resolve('Success');
});
//----等同于----
Promise.resolve('Success');
- 这段代码会让这个Promise对象立即进入
resolved
状态,并将结果success
传递给then
指定的onFulfilled
回调函数。由于Promise.resolve()
也是返回Promise对象,因此可以用.then()
处理其返回值。
Promise.resolve('success').then(function (value) {
console.log(value);
});
-------output-------
Success
//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对象。
var p1 = Promise.resolve({
then: function (resolve, reject) {
resolve("this is an thenable object!");
}
});
console.log(p1 instanceof Promise); // => true
p1.then(function(value) {
console.log(value); // => this is an thenable object!
}, function(e) {
//not called
});
- 无论是在什么时候抛异常,只要promise状态变成resolved或rejected,状态不会再改变,这和新建promise是一样的。
//在回调函数前抛异常
var p1 = {
then: function(resolve) {
throw new Error("error");
resolve("Resolved");
}
};
var p2 = Promise.resolve(p1);
p2.then(function(value) {
//not called
}, function(error) {
console.log(error); // => Error: error
});
//在回调函数后抛异常
var p3 = {
then: function(resolve) {
resolve("Resolved");
throw new Error("error");
}
};
var p4 = Promise.resolve(p3);
p4.then(function(value) {
console.log(value); // => Resolved
}, function(error) {
//not called
});
6 .reject() - 立即执行Promise-reject
语法:
Promise.reject(reason)
和上述的Promise.resolve()类似,它也是new Promise()的快捷方式。
Promise.reject(new Error('error'));
/*******等同于*******/
new Promise(function (resolve, reject) {
reject(new Error('error'));
});
这段代码会让这个Promise对象立即进入rejected状态,并将错误对象传递给then指定的onRejected回调函数。
* Promise 几个应用
Promise
中的.then
方法,可以接收构造函数中处理的状态的变化,并且分别对应执行。.then
有两个函数参数,分别接收resolved
和rejected
的执行。
简单来说, then
就是定义resolve
和reject
函数的,其resolve
函数相当于:
function resolveFun(data) {
// data 为 promise中resolve函数中所带的参数
}
Promise新建后就会立即执行。而then
方法中指定的回调函数,将在当前脚本所有同步任务执行完才会执行。如下例:
1. 执行顺序
javascript代码
var promise = new Promise(function(resolve, reject) {
console.log('before resolved');
resolve();
console.log('after resolved');
});
promise.then(function() {
console.log('resolved');
});
console.log('outer');
-------output-------
// before resolved
// after resolved
// outer
// resolved
2.调用延时执行函数
function timeout (ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done'); // 三个参数?往下看
})
}
timeout(100).then((value) => {
console.log(value)
})
// 输出 done
该例写了一个延时调用函数,设置ms
时间以后,才将Promise的状态修改为resolve
,然后执行.then
中的打印操作。
这里埋了个点,比较有意思。当给setTimeout()传入大于两个参数时,从第三个开始代表的是传给延时执行函数的参数,想具体了解的可以戳这里
3. 异步加载图片
function loadImgAsync (url) {
return new Promise(function (resolve, reject) {
var img = new Image();
image.onload = function () {
resolve(image);
};
image.onerror = function() {
reject(new Error('Could not load image at ' + url));
}
image.src = url;
})
}
上诉的例子中,先加载图片,如果图片加载成功,就调用resolve
,否则调用reject
。
4. 用Promise实现一个Ajax操作
var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
// 封装一个get请求的方法
function getJSON(url) {
return new Promise(function(resolve, reject) {
var XHR = new XMLHttpRequest();
XHR.open('GET', url, true);
XHR.send();
XHR.onreadystatechange = function() {
if (XHR.readyState == 4) {
if (XHR.status == 200) {
try {
var response = JSON.parse(XHR.responseText);
resolve(response);
} catch (e) {
reject(e);
}
} else {
reject(new Error(XHR.statusText));
}
}
}
})
}
getJSON(url).then(resp => console.log(resp));
为了健壮性,处理了很多可能出现的异常,总之,成功了就resolve,失败了就reject。
如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例
现在所有的库几乎都将ajax请求利用Promise进行了封装,因此我们在使用jQuery等库中的ajax请求时,都可以利用Promise来让我们的代码更加优雅和简单。这也是Promise最常用的一个场景
5. resolve参数为另一个Promise实例 - 难点
var p1 = new Promise(function(resolve, reject) {
// ..some code
})
var p2 = new Promise(function(resolve, reject){
// ..some code
resolve(p1)
})
上述中,p1和p2都是一个实例,定义了之后都立即执行,但是p2的resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作
注意:这时,p1的状态决定了p2的状态,如果p1的状态是pending,那么,p2的回调函数就会等待p1状态的改变,如果p1的状态已经是resolve或rejected,那么p2就会立即被执行。
很典型的一个例子
var p1 = new Promise(function(resolve, reject){
setTimeout(() => reject(new Error('Fail')), 3000)
})
var p2 = new Promise(function(resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2.then(result => conosle.log(result))
.catch(error => console.log(error))
// 建议大家看一下浏览器输出效果
// 输出 Error: fail
分析
上述代码中,p1和p2被定义后都立即异步执行,p1执行3秒之后返回reject
,p2执行1秒后返回resolve
,但p2的返回结果是p1,所以,又要等待2秒p1返回结果,即p2的返回结果是“p1的返回结果”,这样大家就明白了,最终执行的其实是p1的结果reject
,所以p2这里调用.catch
而不是.then
。
注意:调用resolve
或reject
并不会终结Promise的参数函数的执行。
new Promise(function(resolve, reject) {
resolve(1);
console.log(2);
}).then(val => {
console.log(val)
})
// 2
// 1
上面代码中,调用resolve(1)
以后,后面的console.log(2)
还是会执行,并且会首先打印出来。这是因为立即 resolved
的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。虽然有这种策略,但我们一般习惯还是将其放在最后。
6. 聊天系统获取两个用户的信息 - 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']
});
7. 多个异步任务提高容错率 - Promise.race()
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
console.log(result); // 'P1'
});
由于p1
执行较快,Promise的then()
将获得结果'P1'。p2仍在继续执行,但执行结果将被丢弃。
* Promise常见问题
到这里,相信你已学会使用Promise了,congratulation!
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了错误
/* 例4.1 */
function taskA() {
console.log(x);
console.log("Task A");
}
function taskB() {
console.log("Task B");
}
function onRejected(error) {
console.log("Catch Error: A or B", error);
}
function finalTask() {
console.log("Final Task");
}
var promise = Promise.resolve();
promise
.then(taskA) // 抛出错误,不继续Task A”
.then(taskB) // .then没有捕获A抛出的错,不打印 “Task B”
.catch(onRejected) // 捕获了A的错,打印错误信息
.then(finalTask); // 错误已经被捕获,执行resolve
-------output-------
Catch Error: A or B,ReferenceError: x is not defined
Final Task
来看一下该例的流程
很明显,A抛错时,会按照
taskA → onRejected → finalTask
这个流程来处理。A抛错后,若没有对它进行处理,状态就会维持rejected
,taskB不会执行,直到catch
了错误。
3. 每次调用then都会返回一个新创建的promise对象,而then内部只是返回的数据
//方法1:对同一个promise对象同时调用 then 方法
var p1 = new Promise(function (resolve) {
resolve(100);
});
p1.then(function (value) {
return value * 2;
});
p1.then(function (value) {
return value * 2;
});
p1.then(function (value) {
console.log("finally: " + value);
});
-------output-------
finally: 100
then
的调用几乎是同时开始执行的,且传给每个then的value都是100,这种方法应当避免。正确的应该是采用链式调用。
//方法2:对 then 进行 promise chain 方式进行调用
var p2 = new Promise(function (resolve) {
resolve(100);
});
p2.then(function (value) {
return value * 2;
}).then(function (value) {
return value * 2;
}).then(function (value) {
console.log("finally: " + value);
});
-------output-------
finally: 400
或许上面这个案例你还没感觉,来看看这个:
function badAsyncCall(data) {
var promise = Promise.resolve(data);
promise.then(function(value) {
//do something
return value + 1;
});
return promise;
}
badAsyncCall(10).then(function(value) {
console.log(value); //想要得到11,实际输出10
});
-------output-------
10
正确的写法应该是:
function goodAsyncCall(data) {
var promise = Promise.resolve(data);
return promise.then(function(value) {
//do something
return value + 1;
});
return promise;
}
goodAsyncCall(10).then(function(value) {
console.log(value);
});
-------output-------
11
4. 在异步回调中抛错,不会被catch到
// Errors thrown inside asynchronous functions will act like uncaught errors
var promise = new Promise(function(resolve, reject) {
setTimeout(function() {
throw 'Uncaught Exception!';
}, 1000);
});
promise.catch(function(e) {
console.log(e); //This is never called
});
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
花了两天工作之余的时间,总算写完了~~看了很多资源,借鉴了许多观点和例子,希望能帮到大家
参考资源:
阮一峰的ES6 教程
廖雪峰的官方网站
Promise迷你书
MDN Promise
廖雪峰的官网能直接在里面自定义代码尝试运行,挺有意思。