无法在Promise内部调用navigator.clipboard.writeText。

huangapple go评论133阅读模式
英文:

Unable to call navigator.clipboard.writeText from within Promise

问题

我目前正在尝试在实际执行navigator.clipboard.writeText(...)之前检查读/写剪贴板权限,但似乎writeText没有被调用。当我尝试粘贴刚刚复制的内容时,它会粘贴先前复制的项目。

以下是我的代码。

const permissionsCheck = async () => {
    let read = await navigator.permissions.query({name: 'clipboard-read'})
    let write = await navigator.permissions.query({name: 'clipboard-write'})
    return write.state === 'granted' && read.state !== 'denied'
}

const updateClipboard = (content) => { 
  navigator.clipboard.writeText(content).then(() => {
        console.log('Copied links!')
        return true
      /* 剪贴板成功设置 */
    }, () => {
        console.log('无法复制链接!')
        return false
    });
}

const init = async () => {
    await permissionsCheck().then(allowed => {
        if (allowed){
           updateClipboard('Hello world')
        } else {
            alert('未授权')
        }
    })

} 

init()

我还尝试将init设置为非异步的方式,如下所示。

var init = () => {
    permissionsCheck().then(allowed => {
        if (allowed){
           updateClipboard('Hello world')
        } else {
            alert('未授权')
        }
    })
}

我还尝试了这种语法。

var init = () => {
    const allowed = permissionsCheck()
    if (allowed){
        updateClipboard('Hello world')
    } else {
        alert('未授权')
    }
}

我用第二和第三种方式写的问题是,权限结果作为Promises返回(因为checkPermissions是异步的),因此结果不一致。有时复制会成功,有时会先弹出警报,然后在第二或第三次尝试时才起作用。

期望的行为

init等待权限 Promise 解析。一旦解析完成,运行updateClipboard(如果权限为正)。似乎我无法找到等待权限结果返回并有效执行writeText之间的平衡点,writeText也是异步的。

我查阅了Mozilla文档并搜索了Stack,但没有找到类似我的用例(或者没有找到明确描述我正在寻找的方式)。任何建议将不胜感激。

以下是代码片段,但在Stack Overflow上它一直返回false,所以我在CodePen上打开了一个CodePen,使用相同的代码在那里运行得更好。

<!-- 开始代码片段:js 隐藏:false 控制台:true babel:false -->

<!-- 语言:lang-js -->

const permissionsCheck = async () => {
    let read = await navigator.permissions.query({name: 'clipboard-read'})
    let write = await navigator.permissions.query({name: 'clipboard-write'})
    return write.state === 'granted' && read.state !== 'denied'
}

const updateClipboard = (content) => { 
  navigator.clipboard.writeText(content).then(() => {
        console.log('Copied links!')
        return true
      /* 剪贴板成功设置 */
    }, () => {
        console.log('无法复制链接!')
        return false
    });
}

const init = async () => {
    await permissionsCheck().then(allowed => {
        if (allowed){
           updateClipboard('Hello world')
        } else {
            alert('未授权')
        }
    })
}

init()

<!-- 结束代码片段 -->
英文:

I am currently trying to check for read/write clipboard permissions before I actually execute navigator.clipboard.writeText(...) but it doesn't look like the writeText is being called. When I try to paste what I just copied, it pastes the previously copied item.

Below is my code.

const permissionsCheck = async () =&gt; {
    let read = await navigator.permissions.query({name: &#39;clipboard-read&#39;})
    let write = await navigator.permissions.query({name: &#39;clipboard-write&#39;})
    return write.state === &#39;granted&#39; &amp;&amp; read.state != &#39;denied&#39;
}

const updateClipboard = (content) =&gt; { 
  navigator.clipboard.writeText(content).then(() =&gt; {
        console.log(&#39;Copied links!&#39;)
        return true
      /* clipboard successfully set */
    }, () =&gt; {
        console.log(&#39;Could not copy links!&#39;)
        return false
    });
}

const init = async () =&gt; {
    await permissionsCheck().then(allowed =&gt; {
        if (allowed){
           updateClipboard(&#39;Hello world&#39;)
        } else {
            alert(&#39;NOT ALLOWED&#39;)
        }
    })

} 

init()

I also tried to write it where init wasn't asynchronous, like so.

var init = () =&gt; {
    permissionsCheck().then(x=&gt;{
        if (allowed){
           updateClipboard(&#39;Hello world&#39;)
        } else {
            alert(&#39;NOT ALLOWED&#39;)
        }
    })

}

I also tried this syntax.

var init = () =&gt; {
    const allowed = permissionsCheck()
    if (allowed){
        updateClipboard(&#39;Hello world&#39;)
    } else {
        alert(&#39;NOT ALLOWED&#39;)
    }
}

The problem with that second and third way I wrote it is that the permissions results were coming back as Promises (as checkPermissions is async), so the results were inconsistent. Sometimes the copy would work, other times it would give the alert first and then work on the second or third try.

Expected Behavior

init waits for the permissions Promise to resolve. Once it's resolved, run updateClipboard (if permissions come back positive). It seems like I can't find the happy medium between waiting for the permission results to come back AND executing writeText effectively, which is also asynchronous.

I've checked out the Mozilla Docs and scoured Stack but haven't found a use case quite like mine (or I haven't found a clear way to describe what I'm looking for). Any advice would be greatly appreciated.

Below is the snippet but on Stack Overflow it keeps returning false so I opened a CodePen using the same code where it works better.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const permissionsCheck = async () =&gt; {
let read = await navigator.permissions.query({name: &#39;clipboard-read&#39;})
let write = await navigator.permissions.query({name: &#39;clipboard-write&#39;})
return write.state === &#39;granted&#39; &amp;&amp; read.state != &#39;denied&#39;

}

const updateClipboard = (content) => {
navigator.clipboard.writeText(content).then(() => {
console.log('Copied links!')
return true
/* clipboard successfully set */
}, () => {
console.log('Could not copy links!')
return false
});
}

const init = async () => {
await permissionsCheck().then(allowed => {
if (allowed){
updateClipboard('Hello world')
} else {
alert('NOT ALLOWED')
}
})

}

init()

<!-- end snippet -->

答案1

得分: 1

以下是翻译好的内容:

尽管在你的实现中似乎没有太大的问题,但你可以在编写异步代码和处理错误的方式上更加一致,以防止并更好地理解代码中的问题:

所以有一些问题:

  • permissionsCheck 可能会失败,所以我建议至少在你的 init 函数中处理它。
  • UpdateClipboard 永远不会返回任何东西,因为你的布尔返回值在承诺完成时调用的回调函数中,因此整个函数将返回 undefined。我建议删除这个逻辑或更改为基于 await 的逻辑。
  • 我建议至少在顶层加入 try...catch 来处理堆栈中的任何承诺拒绝。
  • 为了提高可读性,请尽量避免使用箭头函数表达式来声明函数。
  • 对于文档可能不在焦点的问题,添加一个 document.hasFocus 检查。
async function permissionsCheck() {
	const read = await navigator.permissions.query({
		name: 'clipboard-read',
	});
	const write = await navigator.permissions.query({
		name: 'clipboard-write',
	});
	return write.state === 'granted' && read.state !== 'denied';
}

async function updateClipboard(content) {
	await navigator.clipboard.writeText(content);
	console.log('Copied links!');
}

async function init() {
	try {
		const hasPermissions = await permissionsCheck();

		if (hasPermissions && document.hasFocus()) {
			updateClipboard('Hello world');
		} else {
			alert('NOT ALLOWED');
		}
	} catch (err) {
		console.error(err);
	}
}

init();

在这里,如果调用堆栈的任何部分抛出异常,init 将捕获并记录它。

英文:

While there doesn't seem to be much of an issue in you implementation You could be more consistent in the way you write your asynchronous code and how you handle errors in order to prevent and better understand issues in the code:

So a few issues:

  • permissionsCheck could fail, so I would at least handle this in your init function.
  • UpdateClipboard will never return anything, since your Boolean returns are in the callback functions invoked on promise fulfilment and therefore the overall function will return undefined. I would remove this logic or change to await based logic.
  • I would incorporate a try...catch at least at top level, to handle any promise rejections in your stack.
  • Try to avoid arrow function expressions for declared functions for readability.
  • For your issue where the document may not be in focus, add a document.hasFocus check.
async function permissionsCheck() {
	const read = await navigator.permissions.query({
		name: &#39;clipboard-read&#39;,
	});
	const write = await navigator.permissions.query({
		name: &#39;clipboard-write&#39;,
	});
	return write.state === &#39;granted&#39; &amp;&amp; read.state !== &#39;denied&#39;;
}

async function updateClipboard(content) {
	await navigator.clipboard.writeText(content);
	console.log(&#39;Copied links!&#39;);
}

async function init() {
	try {
		const hasPermissions = await permissionsCheck();

		if (hasPermissions &amp;&amp; document.hasFocus()) {
			updateClipboard(&#39;Hello world&#39;);
		} else {
			alert(&#39;NOT ALLOWED&#39;);
		}
	} catch (err) {
		console.error(err);
	}
}

init();

Here, if any part of this call stack throws, init will catch and log it.

huangapple
  • 本文由 发表于 2023年3月7日 07:14:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75656677.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定