有了Promise
对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise
对象提供统一的接口,使得控制异步操作更加容易。
promise创建后会直接执行
var promise=new Promise(function(resolve,reject){ console.log("异步任务"); resolve(); }) promise.then(function(){ console.log("异步任务完成后,promise状态变为fulfilled,此回调函数被放到消息队列里面,等执行栈空,即下面的代码执行后,再执行此回调函数"); }); console.log("主线程执行")
Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了:
例子1:ajax
var getJSON = function(url) { var promise = new Promise(function(resolve, reject){ var client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler; client.responseType = "json"; client.setRequestHeader("Accept", "application/json"); client.send(); function handler() { if (this.readyState !== 4) { return; } if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } }; }); return promise; }; getJSON("/posts.json").then(function(json) { console.log('Contents: ' + json); }, function(error) { console.error('出错了', error); });
例子2
Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:
job1.then(job2).then(job3).catch(handleError);
其中,job1
、job2
和job3
都是Promise对象。
// 0.5秒后返回input*input的计算结果: function multiply(input) { return new Promise(function (resolve, reject) { log('calculating ' + input + ' x ' + input + '...'); setTimeout(resolve, 500, input * input); }); } // 0.5秒后返回input+input的计算结果: function add(input) { return new Promise(function (resolve, reject) { log('calculating ' + input + ' + ' + input + '...'); setTimeout(resolve, 500, input + input); }); } var p = new Promise(function (resolve, reject) { log('start new Promise...'); resolve(123); }); p.then(multiply) .then(add) .then(multiply) .then(add) .then(function (result) { log('Got value: ' + result); });
例子3
除了串行执行若干异步任务外,Promise还可以并行执行异步任务。
试想一个页面聊天系统,我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是可以并行执行的,用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'] });
例子4
有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用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,就可以把很多异步任务以并行和串行的方式组合起来执行。