覆盖console.log时如何显示Promise对象的状态和值

问题描述

我正在尝试在div中显示console.log输出。我是通过覆盖console.log函数

来实现的

当我使用原始的console.log时,诺言会在控制台中显示为(请参见下面的代码中的1。):

Promise { <state>: "fulfilled",<value>: undefined }

当我超越它时,在div中得到::

 [object Promise]

(请参见下面的代码中的2。)

您如何调整以下代码,以在{main“ div中显示<state>属性

const pause =  sec => new Promise(r => setTimeout(r,1000 * sec))

// 1. Original console.log
;(async function(){
  await new Promise(resolve => document.addEventListener('DOMContentLoaded',resolve));
  let x = pause(0.5)
  console.log(x)
  await x;
  console.log(x)
})();

// 2. Overridden console.log
;(async function(){
  await new Promise(resolve => document.addEventListener('DOMContentLoaded',resolve));
  await pause(1)
  let divconsole = document.getElementById('main');
  // Override console.log:
  console.log = function () {
    for (let i = 0; i < arguments.length; i++) {
      if (typeof arguments[i] === 'object') {
          divconsole.innerHTML += 'console.log arg ' + String(i) + ':  ' + String(arguments[i]) + '<br>';
      }
    }
  }

  let y = pause(0.5)
  console.log(y)
  await y;
  console.log(y)
})();
<div id="main" style="width:100%;height:auto;background-color:lightblue;">

</div>

关于我为什么要问的注释:我的代码带有可在台式机浏览器而不是移动浏览器中解析的承诺。我正在尝试调试(没有一致的移动桌面OS生态系统)。如果可以在一个简单的示例中进行复制,我可能会写一个后续问题。

解决方法

您可以使用this other SO answer中的技巧来处理Promise类型的参数,如下所示。这个技巧要求自定义console.log像这样是异步的:

function promiseState(p) {
    const t = {};
    return Promise.race([p,t])
      .then(v =>
        (v === t) ? { state: "pending" } : { state: "fulfilled",value: v },() => { state: "rejected" }
      );
}

console.log = async function(...args) {
  for (let arg of args) {
    if (arg instanceof Promise) {
      let state = await promiseState(arg);
      divconsole.innerHTML += `Promise { &lt;state&gt;: "${ state.state }"${ state.state === "fulfilled" ? ',&lt;value&gt;: ' + state.value : '' } }<br>`;
    } else if (typeof arg === 'object') {
      divconsole.innerHTML += 'console.log arg:  ' + String(arg) + '<br>';
    }
    // add more else-ifs to handle strings,numbers,booleans,... etc
  }
}

自定义console.log必须为asynchronous,因为它会将承诺包装在另一个承诺中。这是唯一的方法。

说明:

诀窍是针对已解决的承诺race p(产生对象{}),如果承诺p已实现,则其价值为使用,并且由于其价值不能与另一个诺言(我们正在对抗的那个诺言,产生{}的诺言)相同,因此我们确定诺言已兑现。如果我们获得的价值是另一个承诺(对象{})的价值,意味着我们解决的承诺赢得了比赛,那么我们可以确定承诺p尚未兑现。

如果遇到错误(意味着调用catch的回调),则承诺p将被拒绝。

演示:

function promiseState(p) {
  const t = {};
  return Promise.race([p,t])
    .then(v =>
      (v === t) ? { state: "pending" } : { state: "fulfilled",() => { state: "rejected" }
    );
}

console.log = async function(...args) {
  let divconsole = document.getElementById('main');
  
  for (let arg of args) {
    if (arg instanceof Promise) {
      let state = await promiseState(arg);
      divconsole.innerHTML += `Promise { &lt;state&gt;: "${ state.state }"${ state.state === "fulfilled" ? ',&lt;value&gt;: ' + state.value : '' } }<br>`;
    } else if (typeof arg === 'object') {
      divconsole.innerHTML += 'console.log arg:  ' + String(arg) + '<br>';
    }
  }
}

const pause =  sec => new Promise(r => setTimeout(r,1000 * sec));

;(async function() {
  await new Promise(resolve => document.addEventListener('DOMContentLoaded',resolve));
  await pause(1);
  let divconsole = document.getElementById('main');

  let y = pause(0.5);
  await console.log(y);
  await y;
  await console.log(y);
})();
<div id="main" style="width:100%;height:auto;background-color:lightblue;"></div>

,

一种更简单的方法来兑现承诺的真实价值可能是:

async function myLog(val) {
  console.log(await val);
}

await确保兑现承诺,但也可以很好地通过非承诺。