百度一道关于promise笔试题的总结
setTimeout(function () {
console.log(1);
}, 0);
Promise.resolve(function () {
console.log(2);
})
new Promise(function (resolve) {
console.log(3);
});
console.log(4);
输出:3 4 undefined 1
代码解释
链接:https://segmentfault.com/q/1010000011124511?_ea=2530951
js中的事件操作流程主要分为两大类:宏观任务(macro task)与微观任务(micro task),即宏观操作与微观操作
宏任务:全局脚本执行包括setTimeout、setInterval、setImmediate等核心操作符以及I/O交互功能和图形界面渲染。
细粒度任务:涉及process.nextTick事件驱动机制、 promise异步编程模型、Object.observer事件监听器模式以及动态观察模式。
script先参与函数调用栈的操作,在此过程中每当遇到其他 macro tasks 时,则会将 setTimeout 加入到 macro tasks 队列中;而当遇到 micro tasks 时,则将其加入到 micro tasks 队列中。当 function call stack 的所有操作完成并返回后,在 micro tasks 队列完成后会依次先处理完 macro tasks 队列后再重新回到 function call stack 以处理剩余的 micro tasks 队列。
//遇到setTimeout,放入宏仁务队列
setTimeout(function () {
console.log(1);
}, 0);
//遇到promise,放入微任务队列
Promise.resolve(function () {
console.log(2);
})
//这里虽然遇到了promise,但是是用new声明的,也就是立即执行,所以会先输出3
new Promise(function (resolve) {
console.log(3);
});
//第二输出4
console.log(4);
//需要注意的是那个undefined并不是微任务输出的,而是console.log(4)输出的,具体可以控制台测试
----然后执行微任务,这个微任务并没有调用,所以也不会执行,然后执行宏仁务队列中的setTimeout,输出1
代码解释
需要注意之处在于,那个undefined值并非来自微任务处理结果,而是由console.log(4)函数调用产生的。
Promise.resolve(function () {
console.log(2);
})
代码解释
该任务并未被触发因此也不会运行。在扩展的finally()方法中也常采用这种方式因此不被视为错误的做法吗?如何正确处理这个函数的具体实现呢?
这种书写方式并非错误,并非如前所述仅因定义未被调用所导致;具体来说,在Promises.resolve\left(function{\left\{console\log\left(2\right)\right\}}\right).then\left(function{\left\{cb\right\}}{\left\{cb{\left(}\right)}\right)这一场景下,定义并未被触发,因为值传递机制未能实现相应的回调机制连接。而$Promises.resolve{\left(value\right)}中的参数value实际上是在Promises.then{\left(function{\left{value}\right)}{ }\right)内部获取的
new Promise(function (resolve) {
console.log(3);
});
代码解释
尽管遇到了 promise ,而是通过 new 的声明方式来处理。这意味着每当遇到 promise 就会先输出 3。
特别地,在这种情况下,** promise 构造函数所传递进去的函数会在本次 new 操作时就被执行。这是因为异步机制的设计特性决定了操作顺序。
JavaScript运行时采用单线程模型,在同一时间只能处理一段代码。因此,在某一段代码正在进行运行时(即处于活动状态),所有后续的任务都会被加入到一个等待队列中(简称待办事项列表)。当主线程完成当前任务后会切换到下一个等待中的任务进行处理(这通常被称作'阻塞式执行'机制)。因此,在一次鼠标点击事件触发时(无论是直接点击还是间接触发如计时器到达时间点或Ajax请求完成),相关的事件处理程序或回调函数都不会立即开始执行(即不会立即生效),而是会被立即加入到任务队列中等待处理。需要注意的是,在主线程空闲状态下这些等待中的指令才会被依次处理。然而,在某些特殊情况下如果主线程正在处理一段非常耗时的代码序列(例如一个复杂的动画效果或者 intensive 计算),此时发生的一次鼠标点击事件就会导致事件处理程序被阻塞(即暂时无法响应)。这种情况下该事件会被插入到当前主线程结束后才会进行处理的任务队列中(如果设置了 setTimeout 的话)。特别地需要注意的是如果将 setTimeout 设置的时间参数设为 0,则表示该指令会立即插入到队列中但仍然需要等到主线程空闲后再进行实际操作。综上所述 setTimeout 不能保证指令将在指定的时间点被执行其是否及时被执行取决于主线程当时的工作状态是否处于忙碌状态。
所以代码会先执行 new Promise(function(resolve){console.log(3);});
之后调用 console.log 函数输出 4; 该函数返回值为 undefined 最终调用 setTimeout 函数 并在其内部定义一个函数 在延迟时间为零时调用 console.log 输出 1
