promise
异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更加合理且更强大
有三种状态:
1. pending [待定] 初始状态
2. fulfilled [实现] 操作成功
3. rejected [拒绝] 操作失败
var promise = new Promise(function(resolve,reject){
if(/*异步操作*/){
resolve(value);
} else{
reject(error);
}
})
当promise状态发生改变,就会触发then()里的响应函数处理后续步骤
promise.then(函数)
状态改变只有两种可能:
- 从pending变为fulfilled
- 从pending变为rejected
var promise = new Promise(function(resolve,reject){
if(/*异步操作*/){
resolve(value);
} else{
reject(error);
}
}).then(function(result){
console.log(result)
},(function(error){
console.log(error)
})
-
.then 的第一个参数是一个函数,该函数将在 promise resolved 后运行并接收结果。
-
.then 的第二个参数也是一个函数,该函数将在 promise rejected 后运行并接收 error。
如果我们只需要成功的结果 .then()的函数参数可以只有一个
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("success"), 1000);
});
promise.then(result=>alert(result)); // 1 秒后显示 "success"
如果我们只需要失败结果 可以用 .catch() 代替.then()
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject("fail"), 1000);
});
promise.catch(error=>alert(error)); // 1 秒后显示 "fail"
promise链
每个对 .then 的调用都会创建并返回了一个新的 promise,因此我们可以在其之上调用下一个 .then
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
}).then(function(result) { // (***)
alert(result); // 2
return result * 2;
}).then(function(result) {
alert(result); // 4
return result * 2;
});
上面的代码与下面的代码效果相同
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
}).then(function(result) {
alert(result); // 1
return new Promise((resolve, reject) => { // (*)
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) { // (**)
alert(result); // 2
return new Promise((resolve, reject) => {
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) {
alert(result); // 4
});
这里第一个 .then 显示 1 并在 (*) 行返回 new Promise(…)。1 秒后它会进行 resolve,然后 result(resolve 的参数,在这里它是 result*2)被传递给第二个 .then 的处理程序(handler)。这个处理程序(handler)位于 (**) 行,它显示 2,并执行相同的动作(action)。
所以输出与前面的示例相同:1 → 2 → 4,但是现在在每次 alert 调用之间会有 1 秒钟的延迟。
返回 promise 使我们能够构建异步行为链。
promise.all
Promise.all([])可以将多个promise实例包装成一个新的promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败时返回的是最先被reject失败状态的值。
let p1 = new Promise((resolve,reject)=>{
resolve('成功了')
})
let p2 = new Promise((resolve,reject)=>{
resolve('success')
})
let p3 = new Promise((resolve,reject)=>{
reject('失败了')
})
Promise.all([p1,p2]).then((result)=>{
consle.log(result) //['成功了','success'] 结果数组的顺序和all里的数组顺序一致
}).catch((error)=>{
consle.log(error)
})
Promise.all([p1,p3,p2]).then((result)=>{
consle.log(result) //['成功了','success'] 结果数组的顺序和all里的数组顺序一致
}).catch((error)=>{
consle.log(error) //'失败了',其他成功结果被忽略
})
Promise.race
顾名思义,Promise.race就是赛跑的意思,意思就是说,Promise.race([p1,p2,p3])里面哪个结果获得的块,就返回哪个结果,不管结果本身是成果状态还是失败状态。
let p1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('success')
},1000)
})
let p2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('成功了')
},500)
})
let p1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('fail')
},2000)
})
Promise.race([p1,p2,p3]).then((result)=>{
console.log(result) // '成功了',因为p2最先完成
}).catch((error)=>{
consle.log(error)
})
async/await
Async/await 是以更舒适的方式使用 promise 的一种特殊语法,同时它也非常易于理解和使用。
async
在函数前面的 “async” 这个单词表达了一个简单的事情:即这个函数总是返回一个 promise。其他值将自动被包装在一个 resolved 的 promise 中。
async function f() {
return 1;
}
f().then(alert); // 1
这个函数返回一个结果为 1 的 resolved promise,如同下面的代码
async function f() {
return Promise.resolve(1);
}
f().then(alert); // 1
await
await 只在 async 函数内工作
关键字 await 让 JavaScript 引擎等待直到 promise 完成(settle)并返回结果
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // 等待,直到 promise resolve (*)
alert(result); // "done!"
}
f();
这个函数在执行的时候,“暂停”在了 (*) 那一行,并在 promise settle 时,拿到 result 作为结果继续往下执行。所以上面这段代码在一秒后显示 “done!”。
await相当于promise.then
如果一个 promise 正常 resolve,await promise 返回的就是其结果。但是如果 promise 被 reject,它将 throw 这个 error,就像在这一行有一个 throw 语句那样。
async function f() {
await Promise.reject(new Error("Whoops!"));
}
上面代码和下面的是一样的
async function f() {
throw new Error("Whoops!");
}
我们可以用 try…catch 来捕获上面提到的那个 error,与常规的 throw 使用的是一样的方式:
async function f() {
try {
let response = await fetch('http://no-such-url');
} catch(err) {
alert(err); // TypeError: failed to fetch
}
}
f();
总结:
函数前面的关键字 async 有两个作用:
- 让这个函数总是返回一个 promise。
- 允许在该函数内使用 await。
Promise 前的关键字 await 使 JavaScript 引擎等待该 promise settle,然后:
- 如果有 error,就会抛出异常 —— 就像那里调用了 throw error 一样。
- 否则,就返回结果。