JavaScript 用于获取从当前选项卡启动的选项卡的 URL 的书签代码

JavaScript bookmarklet code to get URL of tab that was launched from current tab

我正在尝试开发一个小书签。小书签的目的是显示当前选项卡和因 window.open 调用而启动的新选项卡的 URL。为简单起见,假设 launcher.com 启动随机 URL 访问。

function getBothURLs() { 
    var currentURL, newWin;

    function launchNew () {
        currentURL = window.location.href; 
        newWin     = window.open("https://www.launcher.com");
    }

    launchNew();
    alert(currentURL); 
    alert(newWin.location.href); // displays 'about:blank'
}

我无法获取新启动选项卡的 URL。 alert()(在下面函数的最后)没有正确显示新启动选项卡的 URL;而是显示

 about:blank

当我在 Chrome 控制台中对此进行故障排除时,我将 var currentURL, newWin 的定义移到了 getTwoURLs() 函数的范围之外。当我从控制台调用函数 getBothURLs() 时,currentURLnewWin 都有有效数据。

函数getBothURLs()应该如何修改才能达到预期目的?

来自 MDN 关于 window.open 的注释:

...remote URLs won't load immediately. When window.open() returns, the window always contains about:blank. The actual fetching of the URL is deferred and starts after the current script block finishes executing...

在上述情况下,current 块以 getBothURLs() 函数结束,但您尝试检查该块本身内的新 URL,并且根据上面的引用,你看到 about:blank url.
要解决此问题,只需将查找推迟到下一个任务。您可以使用 setTimeout 之类的东西来 post 查找下一个任务,或者更好的是,如果您希望 return 值,请使用 Promises来自函数。

示例实现可能如下所示:

function getBothURLs() {
  return new Promise((resolve) => {
    var newWin = window.open("//www.whosebug.com");
    setTimeout(() => resolve(newWin))
  }).then((win) => {
    return new Promise((resolve, reject) => {
       var check = setInterval(() => {
         try { 
           if(win.location.href !== "about:blank"){
               clearInterval(check);
               resolve(win.location.href)
           }
         } catch(e) {
           clearInterval(check);
           reject(e);
         }
       }, 50)
     })
   })
}

getBothURLs().then(url => console.log(url))

尽管上述解决方案有效,但我仍然建议您将新 window 的 URL 存储在一个变量中,然后使用该变量调用 open

更新 1:

此示例代码段使用可以 return 两个 url 的非承诺回调版本。虽然,也可以将 promise 版本修改为 return 两个 url,但由于 OP 在评论中要求提供基于非 promise 的版本,所以我提供了新的代码片段。 看看:

function getBothURLs(callback){
  var current = window.location.href;
  var win = window.open("https://whosebug.com");
  var check =  setInterval(() => {
    try {
      if(win.location.href !== "about:blank"){
        clearInterval(check);
        callback(null, current, win.location.href)
      }
    } catch(e) {
      clearInterval(check);
      callback(e);
    }
  }, 50);
}

getBothURLs((err, _cur, _new) => {
  if(err){
    // some error occurred, probably a cross-origin access
    console.error("Failed to get URL", err);
    return;
  }

  console.log(`Current: ${_cur} New: ${_new}`);
})