这里用不用with-eval-after-load?

我抄了一个函数来添加company-backend:

purcell/emacs.d/lisp/init-company.el :

(defun sanityinc/local-push-company-backend (backend)
    "Add BACKEND to a buffer-local version of `company-backends'."
    (make-local-variable 'company-backends)
    (push backend company-backends))

这个函数在用的时候需不需要放在with-eval-after-load 'company里?

e.g.:

(with-eval-after-load 'company
    (add-hook 'c-mode-common-hook
              (lambda () (sanityinc/local-push-company-backend 'company-c-headers))))

以及我该怎么确定,在什么情况下 必须with-eval-after-load, 什么情况下 最好with-eval-after-load, 而什么情况下 不要with-eval-after-load?我看了半天EmacsWiki和官方文档,结果完全理解不到点上……

谢谢!

eval-after-load / with-eval-after-load 的作用非常明确,(elisp) Hooks for Loading 中提到:

If you want code to be executed when a particular library is loaded, use the macro `with-eval-after-load’:

所以问问你自己有没有这个需要?这应该很容易判断,从结果往前推挺别扭,也没听说过什么 best practice 可以总结的。

只要不用的时候不会报错一切都能照预期的来就不用。

谢谢~~看来还是我文档看得少啊……

如果为保安全使用(因为我的菜鸡水平,有时候真判断不出来),开销大不大?

直接不用还可以少写点。用了反而不会安全。

;;; init-foo.el

(require 'foo)

;; 使用 foo 自身的成员,无需 eval-after-load,因为已经 require 在前了
(setq foo/var-a t)

;; 这里的 eval-after-load 多余,foo/func-a 立即被调用
(eval-after-load 'foo
  (foo/func-a))

;; 用到了 bar 的成员,这个包在本文中没有 require,并且:
;;      - 不知道它什么时候/哪个文件 require(抄来的配置太复杂😄)
;;      - 知道它什么时候/哪个文件 require,但是不想为加载顺序所累
;;      - 不/不想关心它什么时候 require
;; 通过 eval-after-load 推迟这段代码的执行,直到 bar 被 require 
(eval-after-load 'bar
  ;; 如果 bar 一直没有 require,就永远也执行不到。有时候可能也会带来些问题
  ;; 比如:你特别需要某个功能,但是这里就静悄悄的跳过去了
  (bar/func-a))

;;; init-foo.el ends here

eval-after-load 开销当然是有一点,但是它里面的代码只在初始化的时候执行一次,如果运用得当,还能节省不少启动时间。你倒是需要注意哪些反复激活的 mode-hook 里的代码开销。

@LdBeth 说少用/不用,那是建立在对初始化流程相当了解的情况下。通常如果配置文件一复杂,难免出现交叉依赖,就像 spacemacs,用了一堆 pre-init/post-init 来解决这个问题。

2 个赞

也就是说,如果我明确的知道这些代码的加载顺序,其实不用也没事?

如果你用 use-package 管理配置的话,你其实是可以完全不需要显式调用 with-eval-after-load 的。