checkCallback判断逻辑优化

这里以 obsidian-sample-plugin 里的例子说明,官方代码如下:

this.addCommand({
	id: 'open-sample-modal-complex',
	name: 'Open sample modal (complex)',
	checkCallback: (checking: boolean) => {
		const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
		if (markdownView) {
			if (!checking) {
				new SampleModal(this.app).open();
			}
			return true;
		}
		return false;
	}
});			

这里的代码是什么意思呢?

通过测试得知,checkCallback 会被调用两次,第一次是按下 mod+p 时(这里的 mod 再 Windows 上是 ctrl,Mac 上是 command),第二次是选择命令时,比如这里当你执行 Open sample modal (complex)命令时。

在第一次时,如果 checkCallback 里返回 false,那么就不会把 Open sample modal (complex)命令加入到命令列表中,那么你也就无法执行命令了。但如果你返回 true,就会加入到命令列表,而不管你判断条件是什么。在第一次执行时,checking 的值总是 true。

第二次执行时,checking 的值,总是 false,这时无论你返回 true 还 false 都没有影响,只有第一次的返回有影响。

总结:

  1. 第一次判断你的返回值决定是否显示命令,这是在弹出命令面板时执行;
  2. 第二次直接执行,不受返回结果影响;
  3. 第一次 checking 传值总是 true,第二次总是 false。

所以你的判断条件是什么,checkCallback api 根本就不关心,那是你自己代码逻辑应该关心的事。

有了上面的了解,可以把上面的代码逻辑做如下优化:

const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
				
if(checking && !markdownView) return false;
if(checking && markdownView) return true;

if(!markdownView) return;

new SampleModal(this.app).open();

嗯,去掉逻辑嵌套,看起来舒服多了。

但是,还不够,每个地方都这样判断,也显得啰嗦,进一步优化:

//定义判断函数
const checkCondition = (checking: boolean, condition: any): boolean|string => {
	//如果预检(第一次执行),且条件不符返回false
	if(checking && !condition) return false;
	//如果预检(第一次执行),且条件符合,返回true
	if(checking && condition) return true;

	//如果非预检(第二次执行),条件不符返回空
	if(!condition) return '';

    //如果非预检(第二次执行),且条件符合返回pass
	return 'pass';
}


//实际使用

const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);

//判断条件是否符合,不符合返回
const checkRet = checkCondition(checking, markdownView)
if('pass' !== checkRet) return Boolean(checkRet);

//条件符合执行
new SampleModal(this.app).open();

这样逻辑看起来简单多了,而且方便复用。

你以为这样就好了,看看1楼lazyloong的回复,我刚开始按照官方逻辑思路整理,被1楼醍醐灌顶了,哈哈。

釜底抽薪式的优化(1楼lazyloong的方式,感谢lazyloong!)

const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);		
if(checking) return Boolean(markdownView) // return condition
new SampleModal(this.app).open();

结束。

1 个赞

我觉得吧,是不是这样可以更简洁

const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);		
if(checking) return Boolean(markdownView) // return condition
new SampleModal(this.app).open();
2 个赞

Boolean 强转还可以直接用俩感叹号

const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);		
if(checking) return !!markdownView;
new SampleModal(this.app).open();

如果乐意的话常量也可以省了,直接俩叹号跟表达式

1 个赞