-
Couldn't load subscription status.
- Fork 1
Description
Promise 是 es6 引入的异步处理方案,让我们可以采用链式的写法注册回调函数,摆脱多层异步回调函数嵌套的情况,使代码更加简洁。
基本用法
用new Promise() 创建一个 Promise 对象:
let p = new Promise((resolve, reject) => {
//
})Promise 对象有3种状态:
pending: 表示进行中的状态fulfilled: 任务完成的状态,调用resolve()后触发rejected: 任务失败的状态, 调用rejected()后触发
状态只能从 pending到 fulfilled,或者 peding 到 rejected。并且状态一旦发生改变,将不会恢复。
Promise对象的 then() 方法,第一个参数为状态变成fulfilled的处理函数,第二个为 rejected 的处理函数。处理函数的参数通过 resolve()方法或者 reject()方法的参数传递:
let p = new Promise((resolve, reject) => {
// 修改promise对象的状态为fulfilled
resolve(1);
});
p.then(v => {
console.log(v); // 1
});catch() 方法同样可以捕获失败状态的 Promise 对象,所以下面两种写法等价:
let p = new Promise((resolve, reject) => {
// 修改promise对象的状态为rejected
reject(new Error('boom'));
});
p.then(null, err => {
console.log(err.message); // boom
});
// 等价于
p.catch(err => {
console.log(err.message); // boom
});在Promise 初始化函数中抛出错误也是变成 rejected 状态:
let p = new Promise((resolve, reject) => {
throw new Error('boom');
});
p.catch(err => {
console.log(err.message); // boom
});对于未处理的错误,catch() 总是能捕捉到。比如上面可以改写成:
let p = new Promise((resolve, reject) => {
throw new Error('boom');
});
p.then(null).catch(err => {
console.log(err.message); // boom
});立即完成的Promise
Promise.resolve() 方法只接收一个参数并返回一个完成态的 Promise:
let p = Promise.resolve(1);
p.then(v => console.log(v)); // 1
// 等价于
let p = new Promise((resolve, reject) => {
resolve(1)
})如果方法传入的是一个非Promise的 thenable 对象,指的是拥有 then()方法并接收 resolve 和 reject 两个参数的普通对象。结果会返回一个新的Promise,并且执行thenable 中的then方法:
let thenable = {
then(resolve, reject) {
resolve(44);
}
};
let p = Promise.resolve(thenable);
p.then(v => console.log(v)); // 44如果传入的是一个Promise 对象,会原封不动的返回这个对象。
另外,通过 Promise.resolve() 创建的对象的 then() 方法执行是在本次事件循环:
setTimeout(() => {
console.log('next event loop');
}, 0);
let p = Promise.resolve('current event loop');
p.then(v => console.log(v));
// current event loop
// next event loop利用 Promise.reject()可以创建立即失败的Promise,参数用法和上面类似。
串行的Promise
其实每次调用then() 和 catch() 方法都会返回一个Promise对象,因此我们可以链式的调用:
let p = Promise.resolve(42);
p.then(v => console.log(v)).then(() => console.log('finish')); // 42 finish在 then() 或者 catch() 方法中抛出错误,会被下一个catch()方法捕获。所以我们推荐在链式的Promise最后一个为 catch():
let p = Promise.resolve(42);
p.then(v => {
console.log(v); // 42
throw new Error('boom');
}).catch(e => {
console.log(e.message); // boom
});在then() 方法中可以return一个值,相当于该值会先作为 Promise.resolve() 参数调用,然后返回一个 Promise 对象,后续的方法调用取决与这个 Promise 的状态:
let p = Promise.resolve(42);
p.then(v => {
console.log(v);
return v + 1; // 相当于 Promise.resolve(v+1);
})
.then(v => {
console.log(v);
})
// 42
// 43返回一个 thenable 对象:
let p = Promise.resolve(42);
let thenable = {
then(resolve, reject) {
reject(44);
}
};
p.then(v => {
console.log(v);
return thenable; // 相当于 Promise.resolve(thenable);
})
.then(v => {
console.log(v);
})
.catch(v => {
console.log('error: ' + v);
});
// 42
// error: 44响应多个Promise
Promise.all() 方法接收一个参数并返回一个 Promise,该参数是含有多个Promise 对象的可迭代元素,例如数组。当每个 Promise对象的状态都为fulfilled 时,返回的 Promise 状态才是 fulfilled:
let p1 = Promise.resolve(1);
let p2 = new Promise((resolve, reject) => {
resolve(2);
});
let p3 = new Promise((resolve, reject) => {
resolve(3);
});
let p = Promise.all([p1, p2, p3]);
p.then(v => console.log(v)); // [ 1, 2, 3 ]只要其中有一个Promise状态为 rejected,最后的返回 Promise的状态就为 rejected:
let p1 = Promise.resolve(1);
let p2 = new Promise((resolve, reject) => {
reject(new Error('boom'));
});
let p3 = new Promise((resolve, reject) => {
resolve(3);
});
let p = Promise.all([p1, p2, p3]);
p.then(v => console.log(v)).catch(e => console.log(e.message)); // 'boom'Promise.race()方法接收的参数和 all()一样,不同的是,传给 race()方法的 Promise 对象只要有一个状态发生改变,返回的 Promise 的状态就会改变,无需等其他的 Promise 状态都改变:
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 0);
});
let p2 = Promise.resolve(2);
let p3 = new Promise((resolve, reject) => {
reject(3);
});
let p = Promise.race([p1, p2, p3]);
p.then(v => console.log(v)).catch(e => console.log(e.message)); // 2异步处理应用
在之前我们有一个模拟的异步任务:
function fetchData(url, cb) {
setTimeout(() => {
cb({ code: 0, data: url });
}, 1000);
}
fetchData('aa.com', res => console.log(res.data)); // aa.com我们可以利用 Promise 的方式改写这个异步任务:
function fetchData(url) {
return new Promise(resolve => {
setTimeout(() => {
resolve({ code: 0, data: url });
}, 1000);
});
}
fetchData('aa.com').then(res => console.log(res.data)); // aa.com对于自动执行函数run()我们可以改写成支持 Promise 异步的形式:
function run(gen) {
let g = gen();
function next(data) {
let result = g.next(data);
if (result.done) return;
let p = Promise.resolve(result.value);
p.then(value => {
next(value);
}).catch(err => {
g.throw(err);
});
}
next();
}