2

我见过很多例子,其中该(set-interval "my-method" n)函数用于在浏览器中每隔 n 秒调用一次函数,但我无法让该set-interval函数运行。

如果我使用:

(ql:quickload :parenscript)
(use-package :parenscript)
(use-package: ps-window-wd-symbols)

我遇到了很多命名空间冲突,set-interval但仍然是一个未定义的函数。

我也尝试过(ps:unobfuscate-package "ps-window-wd-symbols")返回 NIL 并且什么都不做。

这样做的正确方法是什么?

更新:使用(apropos "set-interval")提供:

(apropos "set-interval")
                     SET-INTERVAL
          SMACKJACK::SET-INTERVAL
PS-WINDOW-WD-SYMBOLS:SET-INTERVAL

所以它在两个地方提供。尝试(smackjack::set-interval NIL NIL)还会导致未定义的函数错误。

在我的主项目命名空间中使用M-.返回“No known Symbol”。

4

2 回答 2

3

使用此函数的最佳方法是在 de defmacro ps 中使用它。

如代码中的文档注释所示,您可以找到以下内容:

;; 这些是导出 JS 和浏览器 DOM 的便利包;;符号。如果你:使用包 FOO 中的包,然后 ;; 混淆 FOO,它会阻止 JS 符号获取;;被破坏。

;; 对于大多数 Web 开发任务,您要导入 PS-JS-SYMBOLS,;; PS-WINDOW-WD-SYMBOLS(包括 DOM 级别 2 和 w3c 窗口;;工作草案),可能还有 PS-DOM-NONSTANDARD-SYMBOLS。

并且 set-interval 函数由 ps-window-wd-symbols 包导出,而不是 parenscript 包

defmacro ps:

“给定 Parenscript 表单(隐式 progn),在宏扩展时将这些表单编译为 JavaScript 字符串。扩展为评估为字符串的表单。

看看以下要点

    (ql:quickload :parenscript)
(ql:quickload :cl-who)
(ql:quickload :clack)
(in-package :ps)
(defvar *canvas-id* "alien-canvas")
(clack:clackup
 (lambda (env)
   (list 200
         '(:content-type "text/html")
         (list
          (who:with-html-output-to-string (*standard-output* nil :prologue t :indent t)
            (:html
             (:head
              (:script  :type "text/javascript"
               (who:fmt "~A"
                        (ps (defvar x 0)
                            (defvar y 0)
                            (defvar dx 1)
                            (defvar dy 1)
                            (defvar img (new -image))
                            (setf (@ img src) "http://www.lisperati.com/lisplogo_alien_128.png")
                            (set-interval "draw()" 5)

                            (defun draw ()
                              (let ((w 128)
                                    (h 75)
                                    (canvas ((@ document get-element-by-id) #.*canvas-id*)))
                                (if (or (not canvas) (not (@ canvas get-context)))
                                    (return false))
                                (let ((ctx ((@ canvas get-context) "2d")))
                                  ((@ ctx fill-rect) 0 0 500 500)
                                  (if (and (<= (+ x dx w) 500) (<= 0 (+ x dx)))
                                      (setf x (+ x dx))
                                      (setf dx (* dx -1)))
                                  (if (and (<= (+ y dy h) 500) (<= 0 (+ y dy)))
                                      (setf y (+ y dy))
                                      (setf dy (* dy -1)))
                                  ((@ ctx draw-image) img x y))))))))
             (:body (:canvas :id *canvas-id* :width 500 :height 500))))))))
于 2017-07-24T08:53:18.853 回答
0

AFAIK,set-interval只是一个符号,而不是一个实际的函数(在 Lisp 中)。Parenscript 生成 Javascript 代码,然后可以在 JS 解释器(例如浏览器)中运行,但这不是解释器本身。

Parenscript 提供了一种混淆符号的方法,但也可以保证某些符号不会被混淆。文档说:

由于 Parenscript 对 DOM 或其他 JavaScript 库一无所知,因此库函数和属性名称可能会被无意中混淆。为了帮助防止这种情况,Parenscript 附带了 ps-dom1-symbols、ps-dom2-symbols、ps-window-wd-symbols、ps-dom-nonstandard-symbols 和 ps-dhtml-symbols 符号包,它们定义了各种 DOM 属性和函数标识符作为导出符号(在区分大小写和不区分大小写的变体中),您可以将其导入包中以帮助防止像 pageXOffset 这样的符号被混淆。ps-dhtml-symbols 包包含最广泛的符号并且最常用。

如果您使用混淆和外部 JavaScript 库,您可以使用相同的技术来定义您自己的带有不会被混淆的符号的包。

Smackjack 还产生对setInterval( pusher.lisp:189 ) 的调用,但它不会从上述包中导入符号。这不是一个真正的问题,因为这里只使用了符号的名称,并且没有进行混淆。换句话说,两者smackjack::set-intervalps-window-wd-symbols:set-interval映射到同一个 Javascript 函数。

于 2017-07-24T07:59:07.460 回答