Promise
对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象
相比于使用回调函数callback的模式,Promise的优点是避免了大量回调函数嵌套产生的代码维护性差,可读性差的问题,能将异步操作改写为更简单易读的类似于同步的模式
一个 Promise
有以下几种状态:
- pending: 初始状态。
- fulfilled: 意味着操作成功完成。
- rejected: 意味着操作失败。
所有Promise都有then()方法,它接受两个参数:第一个是当Promise的状态变为fulfilled时要调用的函数,与异步操作相关的附加数据都会传递给这个完成函数(fulfillment function);第二个是当Promise的状态变为rejected时要调用的函数,其与完成时调用的函数类似,所有与失败状态相关的附加数据都会传递给这个拒绝函数(rejection function)
promise.then(function(value) {
// success
}, function(error) {
// failure
});
PS:如果一个对象实现了上述的then()方法,那这个对象我们称之为thenable对象。所有的Promise都是thenable对象,但并非所有thenable对象都是Promise
Promise还有一个catch()方法,相当于只给其传入拒绝处理程序的then()方法
promise.catch(function(error) {
// failure
});
等价于
promise.then(null, function(error) {
// failure
});
Promise.then()详解
因为then和catch方法返回的也是promise 对象, 所以它们可以被链式调用。
回调函数中会把上一个then中返回的值当做参数值供当前then方法调用。每个then也只能使用前一个then的返回值。
let promise =Promise.resolve(111);
promise.then(function(value) {
console.log(value); // 111
return 1;
}).then(function(value) {
console.log(value); // 1
});
then方法执行完毕后需要返回一个新的值给下一个then调用(没有返回值默认使用undefined)。
let promise =Promise.resolve(111);
promise.then(function(value) {
console.log(value); // 111
return 1;
}).then(function(value) {
console.log(value); // undefined
});
then方法若传入非函数,则会忽略当前then方法。
let promise = Promise.resolve(111);
promise.then(1).then(function(value) {
console.log(value); // 111
});
then的处理机制与setTimeout()类似,then中的函数在promise变为完成态后不会立刻执行,而是会置入任务队列等待现有的主线程中的任务全部结束后再进入主线程执行,是典型的异步操作
let promise = new Promise(function(resolve, reject) {
console.log("Promise");
resolve();
});
promise.then(function() {
console.log("Resolved.");
});
console.log("Hi!");
结果
Promise
Hi!
Resolved.
同步异步
任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。
具体来说,异步运行机制如下:
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。