在 JavaScript 世界中, 所有代码都是单线程执行的
异步执行可以可以用回调函数实现
function callback() {
console.log('Done');
}
console.log('before setTimeout()');
setTimeout(callback, 1000);
console.log('after setTimeout()');
`</pre>
先看一个简单的 Promise 例子: 生成0-2之间的随机数, 如果小于1, 则等待一段时间后返回成功, 否则返回失败
<pre>`function test(resolve, reject){
var timeOut = Math.random() * 2;
log('set timeout to: ' + timeOut + ' seconds.');
setTimeout(function(){
if(timeOut < 1) {
log('call resolve()...');
resolve('200 ok');
} else {
log('call reject()...');
reject('timeout in ' + timeOut + ' seconds');
}
}, timeOut * 1000)
}
`</pre>
这个`test()`函数有两个参数, 这两个参数都是函数, 如果执行成功, 我们将调用`resolve('200 ok)'`, 如果执行失败, 我们将调用`reject('timeout in ' + timeOut + ' seconds.')`. 可以看出, `test()`函数只关心自己的逻辑, 并不关心具体的`resolve` 和`reject` 将如何处理.
有了执行函数, 我们就可以用一个 Promise 对象来执行他, 并在将来某个时刻获得成功或失败的结果
<pre>`var p1 = new Promsie(test);
var p2 = p1.then(function(result){
console.log('成功: ' + result);
});
var p3 = p2.catch(function(err){
console.log('失败: ' + err);
});
`</pre>
变量`p1`是一个 Promise 对象, 他负责执行执行`test`函数, 由于`test`函数在内部是异步执行的, 当`test`函数执行到`resolve('ok 200')`时, 告诉 Promsie 对象执行
<pre>`.then(function(result){ // result 是通过 test 传递给 resolve 的参数
console.log('成功: ' + result);
});
`</pre>
当`test`执行到`reject`的时候, 告诉 Promise 对象执行
<pre>`.catch(function(err){ // err 是 test 传递给 reject 的参数
console.log('失败: '+ err);
});
`</pre>
Promise 对象可以串联起来(因为都返回一个 Promise 对象)
<pre>`new Promise(test).then(function(result){console.log(result)}).catch(function(err){console.log(err)});
`</pre>
可见, Promise 最大的好处, 是在异步执行的流程中, 把执行代码和处理结果代码清晰地分离了.
Promise 还可以做更多的事情, 比如有若干个异步任务, 需要先做任务1, 如果成功后再做任务2, 任何任务失败则不再继续并执行错误处理函数
要串行执行这样的异步任务, 只需要链式调用
<pre>`job1.then(job2).then(job3).catch(handleError);
`</pre>
其中 job1, job2, job3 都是(或返回) Promise 对象
<pre>`function job2(input){
return new Promise(function(resolve, reject){
....
})
}
`</pre>
### 并行执行异步任务
试想一个页面聊天任务, 我们需要从两个不同的 URL 分别获取用户的个人信息和好友列表, 这两个任务是可以并行执行的, 用`Promise.all()`实现如下:
<pre>`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']
});
`</pre>
有时多个异步任务是为了容错, 比如同时向两个 URL 读取, 只需要获得先返回的结果, 这种情况下用`Promise.race()`实现:
<pre>`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'
});