Promisification、微任务

前提摘要
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)只有两个参数的转化(最常用)

  1. 接受一个需要被 promise 化的函数 f,并返回一个包装函数(*)。
  2. 包装器返回一个 promise,并将调用转发给原始的 f,并在我们自定义的回调 (**) 中跟踪结果。
// 目标:
// 1. 返回一个promise,在封装的promise里调用原函数
// 2. 调用promise函数时只传除callback的其他参数,内部调用原函数参数要保持一致(加上callback)

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 先显示

解析:

  1. let promise = Promise.resolve(); 创建了一个已经 resolved 的 Promise 对象。
  2. promise.then(() => alert("promise done!")); 给这个 Promise 添加了一个 .then() 回调函数。这个回调函数会在 Promise 状态变为 resolved 时执行,并被放入微任务队列中。
  3. alert("code finished"); 同步代码立即执行,显示 “code finished” 这个 alert。
  4. 当前的同步代码执行完毕后,JavaScript 引擎会检查微任务队列。微任务队列中有一个任务,即在前一步中添加到 Promise 的 .then() 回调函数。
  5. 执行微任务队列中的任务,即执行 .then() 回调函数,显示 “promise done!” 。

示例2: 未处理的 rejection

每个宏任务之后,引擎会立即执行微任务队列中的所有任务,然后再执行其他的宏任务,或渲染,或进行其他任何操作。

如果一个 promise 的 error 未被在微任务队列的末尾进行处理,则会出现“未处理的 rejection”。
如果一个promise返回error,但我们忘记添加 .catch,会被unhandledrejection捕获并报错

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));

解析:

  1. let promise = Promise.reject(new Error("Promise Failed!"))同步代码执行,创建了一个被reject的 Promise 对象。
  2. setTimeout 宏任务被触发,它会在至少 1 秒后将 回调函数添加到微任务队列中。
  3. window.addEventListener()同步执行,添加unhandledrejection 事件监听器,当 Promise 被拒绝且没有被捕获时,unhandledrejection 事件会作为一个宏任务被触发,显示“Promise Failed!”
  4. 所有同步代码执行完毕后,JavaScript 引擎开始执行微任务队列中的任务。这时,第二行代码中的回调函数promise.catch(err => alert('caught')) 被执行,它是一个微任务(会在当前宏任务执行完成后立即执行),显示“caught”。
  • 29
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你脸上有BUG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值