Как не забывать, что вы используете везде в Javascript?

Пытаясь написать небольшое расширение chrome, которое опирается на функции запроса обратного вызова в интерфейсе chrome.*, я быстро приземлился на promises и async/await, так как мне нужно было гарантировать порядок определенных операций, пытаясь избежать callback hell.

Однако, как только я ввел async/await в некоторые функции, каждая функция, которая их использовала, также должна была быть превращена в async function, чтобы иметь возможность await вернуть значение. В конце концов даже некоторые глобальные константы стали promises, например.

const DEBUG = new Promise(function(resolve){
    chrome.management.getSelf(resolve);
}).then(function(self){
    return self.installType == 'development';
});

Однако теперь мне нужно писать await всюду, и появление странных ошибок, таких как if(DEBUG){...}, всегда выполняется слишком просто.

Пока кажется, что можно идентифицировать ошибки с помощью ESLINT, запись await везде кажется излишне громоздкой, и поэтому мне было интересно, если , если Javascript имеет некоторую лучшую конструкцию что мне не хватает?

(Субъективно мое текущее использование await/async кажется обратным, promises хранится как есть, если явно не ожидалось, но мне кажется более желательным, чтобы promises ожидал по умолчанию в async-функциях и сохранялся как голый promises только при явной просьбе.)

Ответ 1

Ввиду отсутствия системы типов, которая позволила бы легко отлавливать такие ошибки (рассматривали ли вы Typescript или Flow?), Вы можете использовать Системную Венгерскую нотацию для имен переменных. Выберите префикс суффикса, например P, Promise или $ и добавьте его ко всем переменным обещания, аналогично тому, как асинхронные функции часто именуются суффиксом Async. Тогда делайте только такие вещи, как

const debug = await debugPromise

где вы можете быстро увидеть, что if (debug) - это хорошо, а if (debugPromise) - нет.


После того, как я ввел async/await в некоторые функции, каждую функцию, которая их использовала, также нужно было превратить в асинхронную функцию, чтобы можно было ожидать возвращаемого значения. В конце концов даже некоторые глобальные константы стали обещаниями

Я бы не стал этого делать. Постарайтесь сделать как можно меньше функций асинхронными. Если они сами не выполняют по сути асинхронные операции, а полагаются только на результаты некоторых обещаний, объявите эти результаты в качестве параметров функции. Простой пример:

// Bad
async function fetchAndParse(options) {
    const response = await fetch(options);
    // do something
    return result;
}
// usage:
await fetchAndParse(options)

// Good:
function parse(response) {
    // do something
    return result;
}
// usage:
await fetch(options).then(parse) // or
parse(await fetch(options))

Тот же самый шаблон может быть применен к глобальным переменным - либо сделайте их явными параметрами каждой функции, либо сделайте их параметрами функции модуля, которая содержит все остальные как замыкания. Затем await глобальных обещаний только один раз в модуле, прежде чем объявлять или выполнять что-либо еще, и впоследствии использовать простое значение результата.

// Bad:
async function log(line) {
    if (await debugPromise)
        console.log(line);
}
async function parse(response) {
    await log("parsing")
    // do something
    return result;
}
… await parse(…) …

// Good:
(async function mymodule() {
    const debug = await debugPromise;
    function log(line) {
        if (debug)
            console.log(line);
    }
    function parse(response) {
        log("parsing")
        // do something
        return result;
    }
    … parse(…) …
}());