前提摘要
Promise 对象的构造器(constructor)语法如下:
let promise = new
Promise(function(resolve, reject) {
// executor
});
传递给 new Promise的函数被称为 executor,当 new Promise 被创建,executor 会自动运行。
Promisification
fication:使成为…,Promisification:使……成为promise
node.js常使用,promisify 是Node.js 标准库 util 模块中的一个函数,用于将遵循Node.js 回调风格的函数转换为返回Promise 的函数,可以使用 async/await 语法来等待异步操作完成,从而让异步代码看起来更像同步代码。
目的: 接受回调的函数 —————————> 一个 返回promise的函数
用法: loadScript(‘path/script.js’, (err, script) => {…} ) —————————> loadScriptPromise(‘path/script.js’).then(…)
promisify(f):
针对callback(err, result)只有两个参数的转化(最常用)
- 接受一个需要被 promise 化的函数 f,并返回一个包装函数(*)。
- 包装器返回一个 promise,并将调用转发给原始的 f,并在我们自定义的回调 (**) 中跟踪结果。
function promisify(f) {
return function (...args) { // (*) // ...args:src
return new Promise((resolve, reject) => {
function callback(err, result) { // 我们对 f 的自定义的回调 (**)
if (err) {
reject(err);
} else {
resolve(result);
}
}
args.push(callback); // 将我们的自定义的回调附加到 f 参数args的末尾,args:[src, callback]
f.call(this, ...args); // 调用原始的函数,
// call第一个参数this:调用原始函数时,保留原始函数(f)中对于 this 关键字的引用,保持上下文一致性。
});
};
}
// 用法:
let loadScriptPromise = promisify(loadScript); // 返回一个包装函数 *
loadScriptPromise(...).then(...); // loadScriptPromise传入src
微任务
- 同步代码是指在当前执行上下文中按顺序执行的代码,不涉及异步操作。当 JavaScript 引擎执行到同步代码时,会一行一行地顺序执行,不会等待其他代码或事件的完成。
- 宏任务是指由 JavaScript 引擎放入任务队列中的任务。它们通常包括整个脚本、setTimeout、setInterval、DOM 事件等。宏任务会在当前执行栈中的所有同步代码执行完毕后才会被执行。
异步任务需要管理,ECMA 标准规定了一个内部队列 PromiseJobs,通常被称为“微任务队列(microtask queue)”。
- 队列(queue)先进先出
- 只有在 JavaScript 引擎中没有其它任务在运行时,才开始执行任务队列中的任务。
示例1
promise 的处理程序 .then、.catch 和 .finally 都是异步的。 当一个 Promise 准备就绪(即状态变为
resolved 或 rejected)时,它的 .then()、.catch()、.finally() 等处理程序会被放入微任务队列中。
let promise = Promise.resolve();
promise.then(() => alert("promise done!"));
alert("code finished"); // 这个 alert 先显示
解析:
let promise = Promise.resolve();
创建了一个已经 resolved 的 Promise 对象。promise.then(() => alert("promise done!"));
给这个 Promise 添加了一个.then()
回调函数。这个回调函数会在 Promise 状态变为 resolved 时执行,并被放入微任务队列中。alert("code finished");
同步代码立即执行,显示 “code finished” 这个 alert。- 当前的同步代码执行完毕后,JavaScript 引擎会检查微任务队列。微任务队列中有一个任务,即在前一步中添加到 Promise 的 .then() 回调函数。
- 执行微任务队列中的任务,即执行 .then() 回调函数,显示 “promise done!” 。
示例2: 未处理的 rejection
每个宏任务之后,引擎会立即执行微任务队列中的所有任务,然后再执行其他的宏任务,或渲染,或进行其他任何操作。
let promise = Promise.reject(new Error("Promise Failed!"));
setTimeout(() => promise.catch(err => alert('caught')), 1000);
// Error: Promise Failed!
window.addEventListener('unhandledrejection', event => alert(event.reason));
解析:
let promise = Promise.reject(new Error("Promise Failed!"))
同步代码执行,创建了一个被reject的 Promise 对象。setTimeout
宏任务被触发,它会在至少 1 秒后将 回调函数添加到微任务队列中。window.addEventListener()
同步执行,添加unhandledrejection
事件监听器,当 Promise 被拒绝且没有被捕获时,unhandledrejection
事件会作为一个宏任务被触发,显示“Promise Failed!”- 所有同步代码执行完毕后,JavaScript 引擎开始执行微任务队列中的任务。这时,第二行代码中的回调函数
promise.catch(err => alert('caught'))
被执行,它是一个微任务(会在当前宏任务执行完成后立即执行),显示“caught”。