Promise
1.如何使用 promise
虽然认识 promise 很久了,但是一直很排斥这个东西,突然来了兴趣,想要仔细研究一下。
MDN文档 可以看这里 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises
promise是一个实现异步编程的方式,它就是一个对象,代表异步操作的最终状态,作为一个函数返回的对象,我们可以在它上面绑定回调函数,而不需要在开始时将回调函数作为参数传入,避免多重回调函数造成的回调地狱。
const promise = initalize(fir);
promise.then(function1, function2);
这样,就将function1 和 function2 绑定作为initalize函数的回调,称为异步调用。
2.Promise对象的特点
- 对象的状态不受外界影响:
一个promise对象代表一个异步操作, pending进行中, resolve|fulfilled完成, rejected失败,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作无法改变状态。
还有 finally()中的函数总会被执行。
- 一旦状态改变,不会在变,任何时候都可以得到这个结果
promise对象的状态改变只有2中可能,pending变为resolve, pending变为rejected
只要发生上面2中变化,状态就会凝固保持,就算发生改变,再对promise对象添加回调函数也会立即得到这个结果。
3.异步调用的优点
1.链式调用:连续执行几个异步操作,上一个操作执行success后,带着执行结果去执行下一个操作。
doSomething().then(function(result) {
return doSomethingElse(result);
})
.then(function(newResult) {
return doThirdThing(newResult);
})
.then(function(finalResult) {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
简写为:
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
2.错误传递: 只需在尾部调用一次
doSomething()
.then(result => doSomethingElse(value))
.then(newResult => doThirdThing(newResult))
.then(finalResult => console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);
3.时序: 即时一个已经为resolve状态的Promise,传递给then()的函数也会被异步调用。
Promise.resolve().then(() => console.log(2));
console.log(1); // 1, 2
注意:传递到 then() 中的函数被置入了一个微任务队列,而不是立即执行,这意味着它是在 JavaScript 事件队列的所有运行时结束了,事件队列被清空之后,才开始执行:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait().then(() => console.log(4));
Promise.resolve().then(() => console.log(2)).then(() => console.log(3));
console.log(1); // 1, 2, 3, 4
4.小试牛刀
1.函数执行顺序 宏任务与微任务
console.log('script start');
setTimeout(() => {
console.log("timer1 over");
}, 0);
Promise.resolve().then(() => {
console.log('promise1');
}).then(() => {
console.log('promise2');
});
console.log('script end');
2.经典题 https://blog.csdn.net/MFWSCQ/article/details/105109727
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(()=>{
console.log('setTimeout');
},0)
async1();
new Promise((resolve)=>{
console.log('promise1');
resolve();
}).then(()=>{
console.log('promise2');
});
console.log('script end');
解析: 微任务的执行优先于宏任务;promise只要被定义就会立即执行;resolve和reject是异步执行的回调;await执行完,会让出线程。
宏任务: setTimeout setInterval script的全部代码
微任务:promise process.nextTick为node独有 Objcet.observe废弃
挂起任务时,js引擎会将所有任务分到宏任务和微任务队列,首先从宏任务队列取出一个任务,执行完毕后执行微任务队列中的所有任务顺序执行;然后,再从宏任务中取出第二个任务,重复上述过程,直至两个队列中的任务被取完。
流程:
1.执行 同步任务 console.log('script start');
2.遇到 setTimeout 把 console.log('setTimeout') 放到 macrotask 宏任务队列中,未执行;
3.执行async1 输出 async1 start,继而执行async2,把 console.log('async1 end');放入 microtask微任务队列中;
4.执行 new promise, 被定义就立即执行,输出 promise1,将console.log('promise2');放入 microtask微任务队列中;
5.执行同步任务 script end;
6.这样所有的macrotask任务执行完,开始执行micro微任务队列中的,顺序输出 async2 和 promise2
7.此轮中的宏任务执行完毕,开始执行宏任务队列中的下一个任务 也就是 setTimeout,输出 setTimeout
结果:
script start async1 start async2 promise1 script end async1 end promise2 setTimeout