Bug 1347894 - Remove uses of defer in devtools/client/scratchpad. r=jdescottes
authorsreeise <reeisesean@gmail.com>
Fri, 05 Oct 2018 16:19:14 +0000
changeset 495585 48715242d46a18214ccbe4692b4d77b5110268a2
parent 495584 3e75d7c78e42350683289433ff419c975d63fafc
child 495586 2d5a9a9d3baa744707c58eec07f9c20e65869d30
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes
bugs1347894
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1347894 - Remove uses of defer in devtools/client/scratchpad. r=jdescottes Promises using defer are being replaced by new Promise and async await syntax. This is for the devtools/client/scratchpad directory. Also includes refactoring of scratchpad for async await. Differential Revision: https://phabricator.services.mozilla.com/D7247
devtools/client/scratchpad/panel.js
devtools/client/scratchpad/scratchpad.js
devtools/client/scratchpad/test/browser_scratchpad_recent_files.js
devtools/client/scratchpad/test/head.js
--- a/devtools/client/scratchpad/panel.js
+++ b/devtools/client/scratchpad/panel.js
@@ -1,55 +1,53 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const EventEmitter = require("devtools/shared/event-emitter");
-const promise = require("promise");
-const defer = require("devtools/shared/defer");
 
 function ScratchpadPanel(iframeWindow, toolbox) {
   const { Scratchpad } = iframeWindow;
   this._toolbox = toolbox;
   this.panelWin = iframeWindow;
   this.scratchpad = Scratchpad;
 
   Scratchpad.target = this.target;
   Scratchpad.hideMenu();
 
-  const deferred = defer();
-  this._readyObserver = deferred.promise;
-  Scratchpad.addObserver({
-    onReady: function() {
-      Scratchpad.removeObserver(this);
-      deferred.resolve();
-    }
+  this._readyObserver = new Promise(resolve => {
+    Scratchpad.addObserver({
+      onReady() {
+        Scratchpad.removeObserver(this);
+        resolve();
+      }
+    });
   });
 
   EventEmitter.decorate(this);
 }
 exports.ScratchpadPanel = ScratchpadPanel;
 
 ScratchpadPanel.prototype = {
   /**
    * Open is effectively an asynchronous constructor. For the ScratchpadPanel,
    * by the time this is called, the Scratchpad will already be ready.
    */
-  open: function() {
+  open() {
     return this._readyObserver.then(() => {
       this.isReady = true;
       this.emit("ready");
       return this;
     });
   },
 
   get target() {
     return this._toolbox.target;
   },
 
-  destroy: function() {
+  destroy() {
     this.emit("destroyed");
-    return promise.resolve();
+    return Promise.resolve();
   }
 };
--- a/devtools/client/scratchpad/scratchpad.js
+++ b/devtools/client/scratchpad/scratchpad.js
@@ -47,18 +47,16 @@ const VARIABLES_VIEW_URL = "chrome://dev
 const {require, loader} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
 
 const Editor = require("devtools/client/sourceeditor/editor");
 const TargetFactory = require("devtools/client/framework/target").TargetFactory;
 const EventEmitter = require("devtools/shared/event-emitter");
 const {DevToolsWorker} = require("devtools/shared/worker/worker");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const flags = require("devtools/shared/flags");
-const promise = require("promise");
-const defer = require("devtools/shared/defer");
 const Services = require("Services");
 const {gDevTools} = require("devtools/client/framework/devtools");
 const { extend } = require("devtools/shared/extend");
 
 const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
 const {NetUtil} = require("resource://gre/modules/NetUtil.jsm");
 const {ScratchpadManager} = require("resource://devtools/client/scratchpad/scratchpad-manager.jsm");
 const {OS} = require("resource://gre/modules/osfile.jsm");
@@ -474,176 +472,144 @@ var Scratchpad = {
   setText: function SP_setText(value) {
     return this.editor.setText(value);
   },
 
   /**
    * Evaluate a string in the currently desired context, that is either the
    * chrome window or the tab content window object.
    *
-   * @param string aString
+   * @param string string
    *        The script you want to evaluate.
    * @return Promise
    *         The promise for the script evaluation result.
    */
-  evaluate: function SP_evaluate(aString) {
+  async evaluate(string) {
     let connection;
     if (this.target) {
       connection = ScratchpadTarget.consoleFor(this.target);
     } else if (this.executionContext == SCRATCHPAD_CONTEXT_CONTENT) {
       connection = ScratchpadTab.consoleFor(this.gBrowser.selectedTab);
     } else {
       connection = ScratchpadWindow.consoleFor(this.browserWindow);
     }
 
     const evalOptions = { url: this.uniqueName };
-
-    return connection.then(({ debuggerClient, webConsoleClient }) => {
-      const deferred = defer();
+    const { debuggerClient, webConsoleClient } = await connection;
+    this.debuggerClient = debuggerClient;
+    this.webConsoleClient = webConsoleClient;
+    const response = await webConsoleClient.evaluateJSAsync(string, null, evalOptions);
 
-      webConsoleClient.evaluateJSAsync(aString, aResponse => {
-        this.debuggerClient = debuggerClient;
-        this.webConsoleClient = webConsoleClient;
-        if (aResponse.error) {
-          deferred.reject(aResponse);
-        } else if (aResponse.exception !== null) {
-          deferred.resolve([aString, aResponse]);
-        } else {
-          deferred.resolve([aString, undefined, aResponse.result]);
-        }
-      }, evalOptions);
-
-      return deferred.promise;
-    });
+    if (response.error) {
+      throw new Error(response.error);
+    } else if (response.exception !== null) {
+      return [string, response];
+    } else {
+      return [string, undefined, response.result];
+    }
   },
 
   /**
    * Execute the selected text (if any) or the entire editor content in the
    * current context.
    *
    * @return Promise
    *         The promise for the script evaluation result.
    */
-  execute: function SP_execute() {
+  execute() {
     WebConsoleUtils.usageCount++;
     const selection = this.editor.getSelection() || this.getText();
     return this.evaluate(selection);
   },
 
   /**
    * Execute the selected text (if any) or the entire editor content in the
    * current context.
    *
    * @return Promise
    *         The promise for the script evaluation result.
    */
-  run: function SP_run() {
-    const deferred = defer();
-    const reject = aReason => deferred.reject(aReason);
-
-    this.execute().then(([aString, aError, aResult]) => {
-      const resolve = () => deferred.resolve([aString, aError, aResult]);
-
-      if (aError) {
-        this.writeAsErrorComment(aError).then(resolve, reject);
-      } else {
-        this.editor.dropSelection();
-        resolve();
-      }
-    }, reject);
-
-    return deferred.promise;
+  async run() {
+    const [string, error, result] = await this.execute();
+    if (error) {
+      await this.writeAsErrorComment(error);
+    } else {
+      this.editor.dropSelection();
+    }
+    return [string, error, result];
   },
 
   /**
    * Execute the selected text (if any) or the entire editor content in the
    * current context. The resulting object is inspected up in the sidebar.
    *
    * @return Promise
    *         The promise for the script evaluation result.
    */
-  inspect: function SP_inspect() {
-    const deferred = defer();
-    const reject = aReason => deferred.reject(aReason);
-
-    this.execute().then(([aString, aError, aResult]) => {
-      const resolve = () => deferred.resolve([aString, aError, aResult]);
-
-      if (aError) {
-        this.writeAsErrorComment(aError).then(resolve, reject);
-      } else {
-        this.editor.dropSelection();
-        this.sidebar.open(aString, aResult).then(resolve, reject);
-      }
-    }, reject);
-
-    return deferred.promise;
+  async inspect() {
+    const [string, error, result] = await this.execute();
+    if (error) {
+      await this.writeAsErrorComment(error);
+    } else {
+      this.editor.dropSelection();
+      await this.sidebar.open(string, result);
+    }
+    return [string, error, result];
   },
 
   /**
    * Reload the current page and execute the entire editor content when
    * the page finishes loading. Note that this operation should be available
    * only in the content context.
    *
    * @return Promise
    *         The promise for the script evaluation result.
    */
-  reloadAndRun: async function SP_reloadAndRun() {
-    const deferred = defer();
-
+  async reloadAndRun() {
     if (this.executionContext !== SCRATCHPAD_CONTEXT_CONTENT) {
       console.error(this.strings
                     .GetStringFromName("scratchpadContext.invalid"));
       return;
     }
 
     const target = await TargetFactory.forTab(this.gBrowser.selectedTab);
-    target.once("navigate", () => {
-      this.run().then(results => deferred.resolve(results));
-    });
-    target.attach().then(() => target.activeTab.reload());
-
-    return deferred.promise;
+    await target.attach();
+    const onNavigate = target.once("navigate");
+    target.activeTab.reload();
+    await onNavigate;
+    await this.run();
   },
 
   /**
    * Execute the selected text (if any) or the entire editor content in the
    * current context. The evaluation result is inserted into the editor after
    * the selected text, or at the end of the editor content if there is no
    * selected text.
    *
    * @return Promise
    *         The promise for the script evaluation result.
    */
-  display: function SP_display() {
-    const deferred = defer();
-    const reject = aReason => deferred.reject(aReason);
-
-    this.execute().then(([aString, aError, aResult]) => {
-      const resolve = () => deferred.resolve([aString, aError, aResult]);
-
-      if (aError) {
-        this.writeAsErrorComment(aError).then(resolve, reject);
-      } else if (VariablesView.isPrimitive({ value: aResult })) {
-        this._writePrimitiveAsComment(aResult).then(resolve, reject);
-      } else {
-        const objectClient = new ObjectClient(this.debuggerClient, aResult);
-        objectClient.getDisplayString(aResponse => {
-          if (aResponse.error) {
-            reportError("display", aResponse);
-            reject(aResponse);
-          } else {
-            this.writeAsComment(aResponse.displayString);
-            resolve();
-          }
-        });
-      }
-    }, reject);
-
-    return deferred.promise;
+  async display() {
+    const [string, error, result] = await this.execute();
+    if (error) {
+      await this.writeAsErrorComment(error);
+      return [string, error, result];
+    } else if (VariablesView.isPrimitive({ value: result })) {
+      await this._writePrimitiveAsComment(result);
+      return [string, error, result];
+    }
+    const objectClient = new ObjectClient(this.debuggerClient, result);
+    const response = await objectClient.getDisplayString();
+    if (response.error) {
+      reportError("display", response);
+      throw new Error(response.error);
+    } else {
+      this.writeAsComment(response.displayString);
+      return [string, error, result];
+    }
   },
 
   _prettyPrintWorker: null,
 
   /**
    * Get or create the worker that handles pretty printing.
    */
   get prettyPrintWorker() {
@@ -797,27 +763,27 @@ var Scratchpad = {
     return functionText;
   },
 
   /**
    * Evaluate the top level function that the cursor is resting in.
    *
    * @returns Promise [text, error, result]
    */
-  evalTopLevelFunction: function SP_evalTopLevelFunction() {
+  evalTopLevelFunction() {
     const text = this.getText();
     const ast = this._parseText(text);
     if (!ast) {
-      return promise.resolve([text, undefined, undefined]);
+      return Promise.resolve([text, undefined, undefined]);
     }
 
     const cursorPos = this.editor.getCursor();
     const funcStatement = this._findTopLevelFunction(ast, cursorPos);
     if (!funcStatement) {
-      return promise.resolve([text, undefined, undefined]);
+      return Promise.resolve([text, undefined, undefined]);
     }
 
     let functionText = this._getFunctionText(funcStatement, text);
 
     // TODO: This is a work around for bug 940086. It should be removed when
     // that is fixed.
     if (funcStatement.type == "FunctionDeclaration"
         && !functionText.startsWith("function ")) {
@@ -842,144 +808,132 @@ var Scratchpad = {
     return this.evaluate(functionText);
   },
 
   /**
    * Writes out a primitive value as a comment. This handles values which are
    * to be printed directly (number, string) as well as grips to values
    * (null, undefined, longString).
    *
-   * @param any aValue
+   * @param any value
    *        The value to print.
    * @return Promise
    *         The promise that resolves after the value has been printed.
    */
-  _writePrimitiveAsComment: function SP__writePrimitiveAsComment(aValue) {
-    const deferred = defer();
-
-    if (aValue.type == "longString") {
+  async _writePrimitiveAsComment(value) {
+    if (value.type == "longString") {
       const client = this.webConsoleClient;
-      client.longString(aValue).substring(0, aValue.length, aResponse => {
-        if (aResponse.error) {
-          reportError("display", aResponse);
-          deferred.reject(aResponse);
-        } else {
-          deferred.resolve(aResponse.substring);
-        }
-      });
+      const response = await client.longString(value).substring(0, value.length);
+      if (response.error) {
+        reportError("display", response);
+        throw new Error(response.error);
+      } else {
+        this.writeAsComment(response.substring);
+      }
     } else {
-      deferred.resolve(aValue.type || aValue);
+      this.writeAsComment(value.type || value);
     }
-
-    return deferred.promise.then(aComment => {
-      this.writeAsComment(aComment);
-    });
   },
 
   /**
    * Write out a value at the next line from the current insertion point.
    * The comment block will always be preceded by a newline character.
-   * @param object aValue
+   * @param object value
    *        The Object to write out as a string
    */
-  writeAsComment: function SP_writeAsComment(aValue) {
-    const value = "\n/*\n" + aValue + "\n*/";
+  writeAsComment(value) {
+    const comment = "\n/*\n" + value + "\n*/";
 
     if (this.editor.somethingSelected()) {
       const from = this.editor.getCursor("end");
-      this.editor.replaceSelection(this.editor.getSelection() + value);
-      const to = this.editor.getPosition(this.editor.getOffset(from) + value.length);
+      this.editor.replaceSelection(this.editor.getSelection() + comment);
+      const to = this.editor.getPosition(this.editor.getOffset(from) + comment.length);
       this.editor.setSelection(from, to);
       return;
     }
 
     const text = this.editor.getText();
-    this.editor.setText(text + value);
+    this.editor.setText(text + comment);
 
-    const [ from, to ] = this.editor.getPosition(text.length, (text + value).length);
+    const [ from, to ] = this.editor.getPosition(text.length, (text + comment).length);
     this.editor.setSelection(from, to);
   },
 
   /**
    * Write out an error at the current insertion point as a block comment
-   * @param object aValue
+   * @param object error
    *        The error object to write out the message and stack trace. It must
    *        contain an |exception| property with the actual error thrown, but it
    *        will often be the entire response of an evaluateJS request.
    * @return Promise
    *         The promise that indicates when writing the comment completes.
    */
-  writeAsErrorComment: function SP_writeAsErrorComment(aError) {
-    const deferred = defer();
-
-    if (VariablesView.isPrimitive({ value: aError.exception })) {
-      const error = aError.exception;
-      const type = error.type;
-      if (type == "undefined" ||
-          type == "null" ||
-          type == "Infinity" ||
-          type == "-Infinity" ||
-          type == "NaN" ||
-          type == "-0") {
-        deferred.resolve(type);
-      } else if (type == "longString") {
-        deferred.resolve(error.initial + "\u2026");
+  writeAsErrorComment(error) {
+    return new Promise(async (resolve, reject) => {
+      const exception = error.exception;
+      if (VariablesView.isPrimitive({ value: exception })) {
+        const type = exception.type;
+        if (type == "undefined" ||
+            type == "null" ||
+            type == "Infinity" ||
+            type == "-Infinity" ||
+            type == "NaN" ||
+            type == "-0") {
+          resolve(type);
+        } else if (type == "longString") {
+          resolve(exception.initial + "\u2026");
+        } else {
+          resolve(exception);
+        }
+      } else if ("preview" in exception) {
+        const stack = this._constructErrorStack(exception.preview);
+        if (typeof error.exceptionMessage == "string") {
+          resolve(error.exceptionMessage + stack);
+        } else {
+          resolve(stack);
+        }
       } else {
-        deferred.resolve(error);
-      }
-    } else if ("preview" in aError.exception) {
-      const error = aError.exception;
-      const stack = this._constructErrorStack(error.preview);
-      if (typeof aError.exceptionMessage == "string") {
-        deferred.resolve(aError.exceptionMessage + stack);
-      } else {
-        deferred.resolve(stack);
-      }
-    } else {
-      // If there is no preview information, we need to ask the server for more.
-      const objectClient = new ObjectClient(this.debuggerClient, aError.exception);
-      objectClient.getPrototypeAndProperties(aResponse => {
-        if (aResponse.error) {
-          deferred.reject(aResponse);
+        // If there is no preview information, we need to ask the server for more.
+        const objectClient = new ObjectClient(this.debuggerClient, exception);
+        const response = await objectClient.getPrototypeAndProperties();
+        if (response.error) {
+          reject(response);
           return;
         }
 
-        const { ownProperties, safeGetterValues } = aResponse;
+        const {ownProperties, safeGetterValues} = response;
         const error = Object.create(null);
 
         // Combine all the property descriptor/getter values into one object.
         for (const key of Object.keys(safeGetterValues)) {
           error[key] = safeGetterValues[key].getterValue;
         }
 
         for (const key of Object.keys(ownProperties)) {
           error[key] = ownProperties[key].value;
         }
 
         const stack = this._constructErrorStack(error);
 
         if (typeof error.message == "string") {
-          deferred.resolve(error.message + stack);
+          resolve(error.message + stack);
         } else {
-          objectClient.getDisplayString(aResponse => {
-            if (aResponse.error) {
-              deferred.reject(aResponse);
-            } else if (typeof aResponse.displayString == "string") {
-              deferred.resolve(aResponse.displayString + stack);
-            } else {
-              deferred.resolve(stack);
-            }
-          });
+          const response = await objectClient.getDisplayString();
+          if (response.error) {
+            reject(response);
+          } else if (typeof response.displayString == "string") {
+            resolve(response.displayString + stack);
+          } else {
+            resolve(stack);
+          }
         }
-      });
-    }
-
-    return deferred.promise.then(aMessage => {
-      console.error(aMessage);
-      this.writeAsComment("Exception: " + aMessage);
+      }
+    }).then((message) => {
+      console.error(message);
+      this.writeAsComment("Exception: " + message);
     });
   },
 
   /**
    * Assembles the best possible stack from the properties of the provided
    * error.
    */
   _constructErrorStack(error) {
@@ -1018,51 +972,50 @@ var Scratchpad = {
    */
   openScratchpad: function SP_openScratchpad() {
     return ScratchpadManager.openScratchpad();
   },
 
   /**
    * Export the textbox content to a file.
    *
-   * @param nsIFile aFile
+   * @param nsIFile file
    *        The file where you want to save the textbox content.
-   * @param boolean aNoConfirmation
+   * @param boolean noConfirmation
    *        If the file already exists, ask for confirmation?
-   * @param boolean aSilentError
+   * @param boolean silentError
    *        True if you do not want to display an error when file save fails,
    *        false otherwise.
-   * @param function aCallback
+   * @param function callback
    *        Optional function you want to call when file save completes. It will
    *        get the following arguments:
    *        1) the nsresult status code for the export operation.
    */
-  exportToFile: function SP_exportToFile(aFile, aNoConfirmation, aSilentError,
-                                         aCallback) {
-    if (!aNoConfirmation && aFile.exists() &&
+  async exportToFile(file, noConfirmation, silentError, callback) {
+    if (!noConfirmation && file.exists() &&
         !window.confirm(this.strings
                         .GetStringFromName("export.fileOverwriteConfirmation"))) {
       return;
     }
 
     const encoder = new TextEncoder();
     const buffer = encoder.encode(this.getText());
-    const writePromise = OS.File.writeAtomic(aFile.path, buffer, {tmpPath: aFile.path + ".tmp"});
-    writePromise.then(value => {
-      if (aCallback) {
-        aCallback.call(this, Cr.NS_OK);
+    try {
+      await OS.File.writeAtomic(file.path, buffer, {tmpPath: file.path + ".tmp"});
+      if (callback) {
+        callback.call(this, Cr.NS_OK);
       }
-    }, reason => {
-      if (!aSilentError) {
+    } catch (error) {
+      if (!silentError) {
         window.alert(this.strings.GetStringFromName("saveFile.failed"));
       }
-      if (aCallback) {
-        aCallback.call(this, Cr.NS_ERROR_UNEXPECTED);
+      if (callback) {
+        callback.call(this, Cr.NS_ERROR_UNEXPECTED);
       }
-    });
+    }
   },
 
   /**
    * Get a list of applicable charsets.
    * The best charset, defaulting to "UTF-8"
    *
    * @param string aBestCharset
    * @return array of strings
@@ -1433,35 +1386,35 @@ var Scratchpad = {
         resolve(aStatus);
       });
     });
   },
 
   /**
    * Save the textbox content to a new file.
    *
-   * @param function aCallback
+   * @param function callback
    *        Optional function you want to call when file is saved
    * @return Promise
    */
-  saveFileAs: function SP_saveFileAs(aCallback) {
+  saveFileAs(callback) {
     return new Promise(resolve => {
       const fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
-      const fpCallback = aResult => {
-        if (aResult != Ci.nsIFilePicker.returnCancel) {
+      const fpCallback = result => {
+        if (result != Ci.nsIFilePicker.returnCancel) {
           this.setFilename(fp.file.path);
-          this.exportToFile(fp.file, true, false, aStatus => {
-            if (Components.isSuccessCode(aStatus)) {
+          this.exportToFile(fp.file, true, false, status => {
+            if (Components.isSuccessCode(status)) {
               this.dirty = false;
               this.setRecentFile(fp.file);
             }
-            if (aCallback) {
-              aCallback(aStatus);
+            if (callback) {
+              callback(status);
             }
-            resolve(aStatus);
+            resolve(status);
           });
         }
       };
 
       fp.init(window, this.strings.GetStringFromName("saveFileAs"),
         Ci.nsIFilePicker.modeSave);
       fp.defaultString = "scratchpad.js";
       fp.appendFilter("JavaScript Files", "*.js; *.jsm; *.json");
@@ -2039,69 +1992,66 @@ ScratchpadTab.prototype = {
   /**
    * The promise for the connection.
    */
   _connector: null,
 
   /**
    * Initialize a debugger client and connect it to the debugger server.
    *
-   * @param object aSubject
+   * @param object subject
    *        The tab or window to obtain the connection for.
    * @return Promise
    *         The promise for the result of connecting to this tab or window.
    */
-  connect: function ST_connect(aSubject) {
+  connect(subject) {
     if (this._connector) {
       return this._connector;
     }
 
-    const deferred = defer();
-    this._connector = deferred.promise;
-
-    const connectTimer = setTimeout(() => {
-      deferred.reject({
-        error: "timeout",
-        message: Scratchpad.strings.GetStringFromName("connectionTimeout"),
-      });
-    }, REMOTE_TIMEOUT);
-
-    deferred.promise.then(() => clearTimeout(connectTimer));
+    this._connector = new Promise(async (resolve, reject) => {
+      const connectTimer = setTimeout(() => {
+        reject({
+          error: "timeout",
+          message: Scratchpad.strings.GetStringFromName("connectionTimeout"),
+        });
+      }, REMOTE_TIMEOUT);
 
-    this._attach(aSubject).then(aTarget => {
-      const consoleActor = aTarget.form.consoleActor;
-      const client = aTarget.client;
-      client.attachConsole(consoleActor, [])
-        .then(([aResponse, aWebConsoleClient]) => {
-          deferred.resolve({
-            webConsoleClient: aWebConsoleClient,
-            debuggerClient: client
-          });
-        }, error => {
-          reportError("attachConsole", error);
-          deferred.reject(error);
+      const target = await this._attach(subject);
+      const consoleActor = target.form.consoleActor;
+      const client = target.client;
+      try {
+        const [, webConsoleClient] = await client.attachConsole(consoleActor, []);
+        clearTimeout(connectTimer);
+        resolve({
+          webConsoleClient,
+          debuggerClient: client
         });
+      } catch (error) {
+        reportError("attachConsole", error);
+        reject(error);
+      }
     });
 
-    return deferred.promise;
+    return this._connector;
   },
 
   /**
    * Attach to this tab.
    *
-   * @param object aSubject
+   * @param object subject
    *        The tab or window to obtain the connection for.
    * @return Promise
    *         The promise for the TabTarget for this tab.
    */
-  _attach: async function ST__attach(aSubject) {
+  async _attach(subject) {
     const target = await TargetFactory.forTab(this._tab);
     target.once("close", () => {
       if (scratchpadTargets) {
-        scratchpadTargets.delete(aSubject);
+        scratchpadTargets.delete(subject);
       }
     });
     return target.attach().then(() => target);
   },
 };
 
 /**
  * Represents the DebuggerClient connection to a specific window as used by the
@@ -2113,40 +2063,38 @@ ScratchpadWindow.consoleFor = Scratchpad
 
 ScratchpadWindow.prototype = extend(ScratchpadTab.prototype, {
   /**
    * Attach to this window.
    *
    * @return Promise
    *         The promise for the target for this window.
    */
-  _attach: function SW__attach() {
+  async _attach() {
     DebuggerServer.init();
     DebuggerServer.registerAllActors();
     DebuggerServer.allowChromeProcess = true;
 
     const client = new DebuggerClient(DebuggerServer.connectPipe());
-    return client.connect()
-      .then(() => client.getProcess())
-      .then(aResponse => {
-        return { form: aResponse.form, client: client };
-      });
+    await client.connect();
+    const response = await client.getProcess();
+    return { form: response.form, client };
   }
 });
 
 function ScratchpadTarget(aTarget) {
   this._target = aTarget;
 }
 
 ScratchpadTarget.consoleFor = ScratchpadTab.consoleFor;
 
 ScratchpadTarget.prototype = extend(ScratchpadTab.prototype, {
-  _attach: function ST__attach() {
+  _attach() {
     if (this._target.isRemote) {
-      return promise.resolve(this._target);
+      return Promise.resolve(this._target);
     }
     return this._target.attach().then(() => this._target);
   }
 });
 
 /**
  * Encapsulates management of the sidebar containing the VariablesView for
  * object inspection.
@@ -2177,67 +2125,65 @@ ScratchpadSidebar.prototype = {
    * Whether the sidebar is currently shown.
    */
   visible: false,
 
   /**
    * Open the sidebar, if not open already, and populate it with the properties
    * of the given object.
    *
-   * @param string aString
+   * @param string string
    *        The string that was evaluated.
-   * @param object aObject
+   * @param object obj
    *        The object to inspect, which is the aEvalString evaluation result.
    * @return Promise
    *         A promise that will resolve once the sidebar is open.
    */
-  open: function SS_open(aEvalString, aObject) {
+  open(string, obj) {
     this.show();
 
-    const deferred = defer();
+    return new Promise(resolve => {
+      const onTabReady = () => {
+        if (this.variablesView) {
+          this.variablesView.controller.releaseActors();
+        } else {
+          const window = this._sidebar.getWindowForTab("variablesview");
+          const container = window.document.querySelector("#variables");
 
-    const onTabReady = () => {
-      if (this.variablesView) {
-        this.variablesView.controller.releaseActors();
-      } else {
-        const window = this._sidebar.getWindowForTab("variablesview");
-        const container = window.document.querySelector("#variables");
-
-        this.variablesView = new VariablesView(container, {
-          searchEnabled: true,
-          searchPlaceholder: this._scratchpad.strings
-                             .GetStringFromName("propertiesFilterPlaceholder")
-        });
+          this.variablesView = new VariablesView(container, {
+            searchEnabled: true,
+            searchPlaceholder: this._scratchpad.strings
+              .GetStringFromName("propertiesFilterPlaceholder")
+          });
 
-        VariablesViewController.attach(this.variablesView, {
-          getEnvironmentClient: aGrip => {
-            return new EnvironmentClient(this._scratchpad.debuggerClient, aGrip);
-          },
-          getObjectClient: aGrip => {
-            return new ObjectClient(this._scratchpad.debuggerClient, aGrip);
-          },
-          getLongStringClient: aActor => {
-            return this._scratchpad.webConsoleClient.longString(aActor);
-          },
-          releaseActor: aActor => {
-            this._scratchpad.debuggerClient.release(aActor);
-          }
-        });
+          VariablesViewController.attach(this.variablesView, {
+            getEnvironmentClient: grip => {
+              return new EnvironmentClient(this._scratchpad.debuggerClient, grip);
+            },
+            getObjectClient: grip => {
+              return new ObjectClient(this._scratchpad.debuggerClient, grip);
+            },
+            getLongStringClient: actor => {
+              return this._scratchpad.webConsoleClient.longString(actor);
+            },
+            releaseActor: actor => {
+              this._scratchpad.debuggerClient.release(actor);
+            }
+          });
+        }
+        this._update(obj).then(resolve);
+      };
+
+      if (this._sidebar.getCurrentTabID() == "variablesview") {
+        onTabReady();
+      } else {
+        this._sidebar.once("variablesview-ready", onTabReady);
+        this._sidebar.addTab("variablesview", VARIABLES_VIEW_URL, {selected: true});
       }
-      this._update(aObject).then(() => deferred.resolve());
-    };
-
-    if (this._sidebar.getCurrentTabID() == "variablesview") {
-      onTabReady();
-    } else {
-      this._sidebar.once("variablesview-ready", onTabReady);
-      this._sidebar.addTab("variablesview", VARIABLES_VIEW_URL, {selected: true});
-    }
-
-    return deferred.promise;
+    });
   },
 
   /**
    * Show the sidebar.
    */
   show: function SS_show() {
     if (!this.visible) {
       this.visible = true;
--- a/devtools/client/scratchpad/test/browser_scratchpad_recent_files.js
+++ b/devtools/client/scratchpad/test/browser_scratchpad_recent_files.js
@@ -232,18 +232,18 @@ var PreferenceObserver = {
       return;
     }
 
     this.branch = Services.prefs.getBranch("devtools.scratchpad.");
     this.branch.addObserver("", this);
     this._initialized = true;
   },
 
-  observe: async function PO_observe(aMessage, aTopic, aData) {
-    if (aTopic != "nsPref:changed") {
+  async observe(message, topic, data) {
+    if (topic != "nsPref:changed") {
       return;
     }
 
     if (this._inProgress) {
       await this._inProgress;
     }
 
     this._inProgress = new Promise(async resolve => {
--- a/devtools/client/scratchpad/test/head.js
+++ b/devtools/client/scratchpad/test/head.js
@@ -6,18 +6,16 @@
 
 const {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm", {});
 const {FileUtils} = ChromeUtils.import("resource://gre/modules/FileUtils.jsm", {});
 const {ScratchpadManager} = ChromeUtils.import("resource://devtools/client/scratchpad/scratchpad-manager.jsm", {});
 const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
 const {gDevTools} = require("devtools/client/framework/devtools");
 const Services = require("Services");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
-const promise = require("promise");
-const defer = require("devtools/shared/defer");
 
 var gScratchpadWindow; // Reference to the Scratchpad chrome window object
 
 /**
  * Open a Scratchpad window.
  *
  * @param function aReadyCallback
  *        Optional. The function you want invoked when the Scratchpad instance
@@ -76,17 +74,17 @@ function openScratchpad(aReadyCallback, 
  *        are supported:
  *        - tabContent
  *          A string providing the html content of the tab.
  * @return Promise
  */
 function openTabAndScratchpad(aOptions = {}) {
   waitForExplicitFinish();
   // eslint-disable-next-line new-cap
-  return new promise(resolve => {
+  return new Promise(resolve => {
     gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
     const {selectedBrowser} = gBrowser;
     BrowserTestUtils.browserLoaded(selectedBrowser).then(function() {
       openScratchpad((win, sp) => resolve([win, sp]), aOptions);
     });
     BrowserTestUtils.loadURI(gBrowser, "data:text/html;charset=utf8," + (aOptions.tabContent || ""));
   });
 }
@@ -123,51 +121,49 @@ function createTempFile(aName, aContent,
   NetUtil.asyncCopy(fileContentStream, fout, function(aStatus) {
     aCallback(aStatus, file);
   });
 }
 
 /**
  * Run a set of asychronous tests sequentially defined by input and output.
  *
- * @param Scratchpad aScratchpad
+ * @param Scratchpad scratchpad
  *        The scratchpad to use in running the tests.
- * @param array aTests
+ * @param array tests
  *        An array of test objects, each with the following properties:
  *        - method
  *          Scratchpad method to use, one of "run", "display", or "inspect".
  *        - code
  *          Code to run in the scratchpad.
  *        - result
  *          Expected code that will be in the scratchpad upon completion.
  *        - label
  *          The tests label which will be logged in the test runner output.
  * @return Promise
  *         The promise that will be resolved when all tests are finished.
  */
-function runAsyncTests(aScratchpad, aTests) {
-  const deferred = defer();
-
-  (function runTest() {
-    if (aTests.length) {
-      const test = aTests.shift();
-      aScratchpad.setText(test.code);
-      aScratchpad[test.method]().then(function success() {
-        is(aScratchpad.getText(), test.result, test.label);
-        runTest();
-      }, function failure(error) {
-        ok(false, error.stack + " " + test.label);
-        runTest();
-      });
-    } else {
-      deferred.resolve();
-    }
-  })();
-
-  return deferred.promise;
+function runAsyncTests(scratchpad, tests) {
+  return new Promise(resolve => {
+    (function runTest() {
+      if (tests.length) {
+        const test = tests.shift();
+        scratchpad.setText(test.code);
+        scratchpad[test.method]().then(function success() {
+          is(scratchpad.getText(), test.result, test.label);
+          runTest();
+        }, function failure(error) {
+          ok(false, error.stack + " " + test.label);
+          runTest();
+        });
+      } else {
+        resolve();
+      }
+    })();
+  });
 }
 
 /**
  * Run a set of asychronous tests sequentially with callbacks to prepare each
  * test and to be called when the test result is ready.
  *
  * @param Scratchpad aScratchpad
  *        The scratchpad to use in running the tests.