我们知道js是异步执行的。那么什么是异步呢?
我理解的异步就是事件完成的顺序与和交付他们的时间顺序无关
。举个例子来说:
你去一家餐厅吃饭,并且找到一个位置坐下,然后你想让服务员给你拿个菜单,但是这个时候服务员站在另一桌吃饭的人旁边等待服务,向你说对不起我不是异步的服务员,我只能服务完这桌人才能来为您服务。你的内心肯定很痛苦吧!!!
所以如果这个服务员是异步的,他应该就是给你拿来菜单。此时,你比那桌人后来,但是服务员仍然为你服务了。
传统的解决异步的方法或多或少都有缺点
以前我们采用回调或者是事件监听来解决异步,但是编程的时候你很容易发现,这不便于你维护,并且你没有办法在外部捕获这个错误,只能通过回调把这个error返回出去;还有一个问题是,假设我们有这样一种应用场景,你需要找出一堆文件中最大的那个文件,但是这个时候你并不知道它什么时候会比较完,所以你可能会设置一个count来计数,这个count应该是放在最顶层的,这个时候问题就出现了,一旦某个函数改变了这个count,我们就会得到错误的结果
这个时候我们有了promise
什么是promise呢,按照MDN官方的解释,promise对象是用于异步操作的,它表示一个尚未完成,并且可能在未来完成或者不完成的异步操作。
这似乎是有些难理解,我认为的promise是能够将异步操作队列化,使之按照我们期望的顺序执行,同时返回符合预期结果的一个对象。
为了理解它,我们先来看一个最为简单的promise
var test = new Promise(resolve=>{
setTimeout(()=>{
resolve('hello');
},1000);
}).then(value=>{
console.log(value + 'world'); //hello,world
})
在promise对象当中,包含着一个执行器,这个执行器需要执行一个异步操作,它耗时会比较长,当它执行完成之后,promise的状态就会变成fullfilled,一旦promise的状态变化了,就会触发then,then的参数value是promise参数中的函数执行后的结果。这其中的resolve是一个函数,它是执行成功时的函数回调。
通过查看promise的源码你会发现,为了让promise的执行器是一个异步函数,resolve当中使用了setTimeout函数
var resolve = function (val) {
if (self.status !== 'pending') {
return;
}
setTimeout(function () {
self.value = val;
self.status = "resolved";
resDeferreds.forEach(function (deferred) {
deferred(self.value);
});
}, 0);
};
看到了最为基本的情况,接下来我们来看一下如果then里面返回了一个promise
会出现什么样的情况呢?
var p = new Promise(function(resolve) {
console.log(1);
console.log(resolve); //resolve是一个函数,它是一个执行成功时的回调函数
setTimeout(function() {
resolve(2);
}, 1000);
})
.then(value => {
console.log(value); //2
return new Promise(resolve => {
setTimeout(() => {
resolve('world');
}, 2000);
})
})
.then(value => {
console.log(value + 'perfect!'); //world perfect
});
执行这段代码,你会发现执行的结果是world perfect
, 因为我们在第一个then的时候在promise中返回了一个resolve(‘world’),如果then之后是一个promise的话 它会等待这个promise执行完成,如果不是的话,它几乎是会立即执行下一个then
那么我们不在then中返回promise
的情况
var promise1 = new Promise(resolve => {
setTimeout(() => {
resolve('hello');
}, 1000)
})
.then(value => {
console.log(value); //hello
console.log('world');
(function() {
return new Promise(resolve => { //这个返回值并不是在then的响应函数里面返回的
setTimeout(() => {
console.log('ywl');
resolve('resolve');
}, 3000)
})
})();
return false; //如果不返回的话,默认传递undefined
})
.then(value => {
console.log(value + ' world'); //false world
});
我们可以看到第二个then中打印出的是false world ,这是因为 第一个then当中的promise不是在then的响应函数里面返回的,而return false
则是,我们自然而然的会想到,如果我不返回呢,这个时候就会默认返回一个undefined,那么最后打印出来的就过就成了 undefiend world
以上的情况都是立即.then,那么如果我对已经完成的promise,执行.then会出现什么样的现象呢?我们来看一下
console.log('promise start!');
let promise = new Promise(resolve => {
setTimeout(() => {
resolve('hello,world');
}, 1000)
})
setTimeout(() => {
promise.then(value => {
console.log(value); //hello,world
});
}, 3000);
我们可以看到打印的结果是hello,world。这意味着我们可以执行同步函数那样,执行异步操作,当有多个回调时,promise的威力就显示出来了。