Самые распространенные вопросы и ответы на собеседованиях по JavaScript в 2019 году

интервью

2019 год прошел, и пиковый сезон интервью в 2020 году снова здесь. После изучения и интервью в 2019 году мы собрали некоторые из наиболее распространенных вопросов для интервью ниже.

Что такое принуждение в JavaScript?

Сложность: легко

В JavaScript преобразование между двумя разными встроенными типами называется приведением. Приведение типов в JavaScript бывает двух видов: явное и неявное.

Вот пример явного приведения:

var a = "42";
var b = Number( a );
a;                // "42" -- 字符串
b;                // 42 -- 是个数字!

Вот пример неявного приведения:

var a = "42";
var b = a * 1;    // "42" 隐式转型成 42 
a;                // "42"
b;                // 42 -- 是个数字!

Что такое область видимости в JavaScript?

Сложность: легко

В JavaScript каждая функция имеет свою область видимости. Область видимости — это, по сути, набор переменных и правил доступа к этим переменным по имени. Только код внутри функции может получить доступ к переменным в области действия функции.

Имена переменных в одной области видимости должны быть уникальными. Область может быть вложена в другую область. Если одна область вложена в другую область, код в самой внутренней области может получить доступ к переменным другой области.

Объясните равенство в JavaScript.

Сложность: легко

В JavaScript есть строгие сравнения и сравнения приведения:

  • Строгие сравнения (например, ===) проверяют, равны ли два значения, не запрещая приведения;
  • Абстрактные сравнения, такие как ==, проверяют, равны ли два значения, допуская приведение типов.
var a = "42";
var b = 42;
a == b;            // true
a === b;        // false

Несколько простых правил:

  • Если какое-либо из сравниваемых значений может быть истинным или ложным, используйте ===, а не ==;
  • Если какие-либо из сравниваемых значений являются этими конкретными значениями (0, "", или []), используйте ===, а не ==;
  • В других случаях == можно безопасно использовать. Это не только безопасно, но во многих случаях упрощает и улучшает читаемость кода.

Объясните, что такое функция обратного вызова, и приведите простой пример.

Сложность: легко

Функция обратного вызова — это функция, которую можно передать в качестве параметра другой функции и выполнить после завершения какой-либо операции. Ниже приведен пример простой функции обратного вызова, которая выводит сообщение на консоль после завершения некоторой операции.

function modifyArray(arr, callback) {
  // 对 arr 做一些操作
  arr.push(100);
  // 执行传进来的 callback 函数
  callback();
}

var arr = [1, 2, 3, 4, 5];

modifyArray(arr, function() {
  console.log("array has been modified", arr);
});

Что делает «использовать строго»?

Сложность: легко

use strict появляется в верхней части кода JavaScript или в верхней части функций, чтобы помочь вам писать более безопасный код JavaScript. Если вы создадите глобальную переменную по ошибке, она предупредит вас об ошибке. Например, следующая программа выдаст ошибку:

function doSomething(val) {
  "use strict"; 
  x = val + 10;
}

Он выдает ошибку, потому что x не определен, и присваивает ему значение из глобальной области видимости, что не позволяет использовать strict. Следующее небольшое изменение исправляет эту ошибку:

function doSomething(val) {
  "use strict"; 
  var x = val + 10;
}

Объясните значение null и undefined в JavaScript.

Сложность: легко

В JavaScript есть два базовых типа: null и undefined. Они представляют разные значения:

  • Вещи, которые еще не были инициализированы:undefined
  • Что сейчас недоступно:null
  • typeof тоже отличается

Напишите функцию, которая делает следующее.

Сложность: легко

var addSix = createBase(6);
addSix(10); // 返回 16
addSix(21); // 返回 27

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

function createBase(baseNumber) {
  return function(N) {
    // 我们在这里访问 baseNumber,即使它是在这个函数之外声明的。
    // JavaScript 中的闭包允许我们这么做。
    return baseNumber + N;
  }
}

var addSix = createBase(6);
addSix(10);
addSix(21);

Интерпретация значений и типов в JavaScript

Сложность: легко

JavaScript имеет типизированные значения, но не типизированные переменные. JavaScript предоставляет следующие встроенные типы:

  • string
  • number
  • boolean
  • нулевой и неопределенный
  • object
  • символ (новое в ES6)
  • bigint

Объясните всплытие событий и как его остановить?

Сложность: легко

Всплывание событий — это когда наиболее глубоко вложенный элемент запускает событие, которое затем запускается в родительском элементе в порядке вложенности.

Одним из способов предотвращения всплытия событий является использование event.cancelBubble или event.stopPropagation() (до IE 9).

Каково использование ключевого слова let в JavaScript?

Сложность: легко

Помимо возможности объявлять переменные на уровне функций, ES6 также позволяет вам объявлять переменные в блоках кода ({..}) с помощью ключевого слова let.

Как проверить, является ли число целым?

Сложность: легко

Очень простой способ проверить, является ли число десятичным или целым, состоит в том, чтобы взять его по модулю 1 и посмотреть, есть ли остаток.

function isInt(num) {
  return num % 1 === 0;
}

console.log(isInt(4)); // true
console.log(isInt(12.2)); // false
console.log(isInt(0.3)); // false

Что такое IIFE (выражение немедленно вызываемой функции)?

Сложность: легко

Это немедленно вызываемое функциональное выражение, или сокращенно IIFE. Функция выполняется сразу после создания:

(function IIFE(){
    console.log( "Hello!" );
})();
// "Hello!"

Как сравнить два объекта в JavaScript?

Сложность: умеренная

Для двух непримитивных значений, таких как два объекта (включая функции и массивы), сравнения == и === проверяют только соответствие их ссылок, а не то, на что на самом деле ссылаются.

Например, по умолчанию массивы преобразуются в строки, а запятые используются для объединения всех элементов массива. Итак, два массива с одинаковым содержимым не будут равны, когда == :

var a = [1,2,3];
var b = [1,2,3];
var c = "1,2,3";

a == c;        // true
b == c;        // true
a == b;        // false

Глубокая копия нищего издания

var obj1 = {
  a: 1,
  b: 2,
  c: 3
}
var objString = JSON.stringify(obj1);
var obj2 = JSON.parse(objString);
obj2.a = 5;
console.log(obj1.a);  // 1
console.log(obj2.a); // 5

Для глубокого сравнения объектов можно использовать библиотеку deep-equal или реализовать алгоритм рекурсивного сравнения самостоятельно.

Объясните разницу между ES5 и ES6?

Сложность: умеренная

  • ECMAScript 5 (ES5): 5-е издание ECMAScript, стандартизированное в 2009 году. Этот стандарт полностью реализован во всех современных браузерах.
  • ECMAScript 6 (ES6) или ECMAScript 2015 (ES2015): 6-е издание ECMAScript, стандартизированное в 2015 году. Этот стандарт частично реализован в большинстве современных браузеров.

Для получения подробной информации вы можете перейти в блог Учителя Жуань Ифэн.

Что такое «закрытие» в Javascript? Например?

Сложность: умеренная

Закрытие — это функция, которая определена внутри другой функции (называемой родительской функцией) и имеет доступ к переменным, объявленным и определенным в области видимости родительской функции.

Замыкания могут обращаться к переменным в трех областях:

  • переменные, объявленные в своей области видимости;
  • переменные, объявленные в родительской функции;
  • Переменные, объявленные в глобальной области видимости.

Пример: Реализация функции защиты от сотрясений || дросселирования

Как создать приватные переменные в JavaScript?

Сложность: умеренная

Чтобы создать приватную переменную в JavaScript, которую нельзя изменить, вам нужно создать ее как локальную переменную в функции. Даже если функция вызывается, переменная не может быть доступна вне функции. Например:

function func() {
  var priv = "secret code";
}

console.log(priv); // throws error

Чтобы получить доступ к этой переменной, создайте вспомогательную функцию, которая возвращает закрытую переменную.

function func() {
  var priv = "secret code";
  return function() {
    return priv;
  }
}

var getPriv = func();
console.log(getPriv()); // => secret code

Пожалуйста, объясните схему прототипирования.

Сложность: умеренная

Шаблон прототипа можно использовать для создания новых объектов, но вместо неинициализированных объектов он создает объекты, инициализированные значениями объекта-прототипа (или объекта-образца). Шаблон прототипа также известен как шаблон свойств.

Шаблон прототипа полезен при инициализации бизнес-объектов, значения которых совпадают со значениями по умолчанию в базе данных. Значения по умолчанию в объекте-прототипе копируются во вновь созданный бизнес-объект.

Классические языки программирования редко используют шаблон прототипа, но JavaScript как язык прототипа использует этот шаблон при построении новых объектов и их прототипов.

Проверяет, является ли данная строка изоморфной.

Сложность: умеренная

Если две строки изоморфны, то все вхождения символов в строку A можно заменить другим символом, чтобы получить строку B, при этом порядок символов должен быть сохранен. Каждый символ в строке A должен однозначно соответствовать каждому символу в строке B.

  • paper и title вернут true.
  • egg и sad вернут false.
  • dgg и add вернут true.
isIsomorphic("egg", 'add'); // true
isIsomorphic("paper", 'title'); // true
isIsomorphic("kick", 'side'); // false

function isIsomorphic(firstString, secondString) {

  // 检查长度是否相等,如果不相等, 它们不可能是同构的
  if (firstString.length !== secondString.length) return false

  var letterMap = {};

  for (var i = 0; i < firstString.length; i++) {
    var letterA = firstString[i],
        letterB = secondString[i];

    // 如果 letterA 不存在, 创建一个 map,并将 letterB 赋值给它
    if (letterMap[letterA] === undefined) {
      letterMap[letterA] = letterB;
    } else if (letterMap[letterA] !== letterB) {
      // 如果 letterA 在 map 中已存在, 但不是与 letterB 对应,
      // 那么这意味着 letterA 与多个字符相对应。
      return false;
    }
  }
  // 迭代完毕,如果满足条件,那么返回 true。
  // 它们是同构的。
  return true;
}

Что означает «Транспиляция»?

Сложность: умеренная

Новые синтаксисы, добавленные в язык, не могут быть полифилами. Таким образом, лучший подход — использовать инструмент, который может преобразовать более новый код в более старый эквивалент. Этот процесс часто называют транспилированием, что означает преобразование + компиляция.

Как правило, в процесс сборки добавляется транспилятор, аналогичный линтеру или минификатору. Сейчас есть много отличных конвертеров на выбор:

  • Babel: перевод ES6+ на ES5
  • Traceur: преобразование ES6, ES7 в ES5

Каково обоснование ключевого слова «это»? Пожалуйста, предоставьте несколько примеров кода.

Сложность: умеренная

В JavaScript это относится к «владельцу» исполняемой функции, а точнее к объекту, который имеет текущую функцию в качестве метода.

function foo() {
    console.log( this.bar );
}

var bar = "global";

var obj1 = {
    bar: "obj1",
    foo: foo
};

var obj2 = {
    bar: "obj2"
};

foo();             // "global"
obj1.foo();        // "obj1"
foo.call( obj2 );  // "obj2"
new foo();         // undefined

Как я могу добавить собственный метод к объекту Array, чтобы приведенный ниже код работал?

Сложность: умеренная

var arr = [1, 2, 3, 4, 5];
var avg = arr.average();
console.log(avg);

JavaScript основан не на классах, а на основе прототипов. Это означает, что каждый объект связан с другим объектом (то есть прототипом объекта) и наследует методы объекта-прототипа. Вы можете отслеживать цепочку прототипов каждого объекта, пока не достигнете нулевого объекта без прототипа. Нам нужно добавить методы к глобальному объекту Array, изменив прототип Array.

Array.prototype.average = function() {
  // 计算 sum 的值
  var sum = this.reduce(function(prev, cur) { return prev + cur; });
  // 将 sum 除以元素个数并返回
  return sum / this.length;
}

var arr = [1, 2, 3, 4, 5];
var avg = arr.average();
console.log(avg); // => 3

Каков результат следующего кода?

Сложность: умеренная

0.1 + 0.2 === 0.3

Вывод этого кода ложный, что вызвано внутренним представлением чисел с плавающей запятой. 0,1 + 0,2 не совсем равно 0,3, фактический результат равен 0,300000000000000004. Одним из решений этой проблемы является округление результата при выполнении арифметических действий с десятичными дробями.

Зачем писать ключ в компоненте при написании проекта React/Vue и какова его роль?

Сложность: умеренная

Функция ключа состоит в том, чтобы быстрее найти соответствующий узел при выполнении алгоритма сравнения и повысить скорость сравнения.

И vue, и react используют алгоритм diff для сравнения старых и новых виртуальных узлов для обновления узлов. в функции сравнения vue. Вы можете сначала понять алгоритм diff.

Во время перекрестного сравнения, когда новый узел и старый узел сравниваются безрезультатно, ключ в массиве старых узлов будет сравниваться в соответствии с ключом нового узла, чтобы найти соответствующий старый узел (здесь соответствует ключу => карта индекса). Если он не найден, он считается новым узлом. Если ключа нет, то для нахождения соответствующего старого узла будет использоваться метод обхода. Один - карта, другой - обходной поиск. в отличие. карта быстрее.

Часть исходного кода vue выглядит следующим образом:

// vue 项目  src/core/vdom/patch.js  -488 行
// oldCh 是一个旧虚拟节点数组,
if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
       idxInOld = isDef(newStartVnode.key)
         ? oldKeyToIdx[newStartVnode.key]
         : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)

Создайте функцию карты:

function createKeyToOldIdx (children, beginIdx, endIdx) {
 let i, key
 const map = {}
 for (i = beginIdx; i <= endIdx; ++i) {
   key = children[i].key
   if (isDef(key)) map[key] = i
 }
 return map
}

Перейдите, чтобы найти:

// sameVnode 是对比新旧节点是否相同的函数
function findIdxInOld (node, oldCh, start, end) {
   for (let i = start; i < end; i++) {
     const c = oldCh[i]

     if (isDef(c) && sameVnode(node, c)) return i
   }
}

Разобрать ['1', '2', '3'].map(parseInt)

Сложность: умеренная

Когда я впервые увидел этот вопрос, ответ, который пришел мне в голову, был [1, 2, 3], но настоящий ответ был [1, NaN, NaN].

Сначала давайте рассмотрим первый обратный вызов параметра функции карты:

  var new_array = arr.map(function callback(currentValue[, index[, array]]) { // Return element for new_array }[, thisArg])

Этот обратный вызов может получить всего три параметра

  • Первый параметр представляет элемент, который в данный момент обрабатывается, а второй параметр представляет индекс элемента.
  • А parseInt используется для анализа строки, превращая строку в целое число по указанной системе счисления.
  • parseInt(string, radix) принимает два параметра, первый — это значение для обработки (строка), а второй — основание при синтаксическом анализе.

Поняв эти две функции, мы можем смоделировать операцию;

  • parseInt('1', 0) //Если основание равно 0, а строковый параметр не начинается с "0x" и "0", он обрабатывается по основанию 10. В это время верните 1;
  • parseInt('2', 1) // Среди чисел, представленных основанием 1 (1 основание), максимальное значение меньше 2, поэтому оно не может быть проанализировано и возвращает NaN;
  • parseInt('3', 2) // Среди чисел, представленных основанием 2 (двоичным), максимальное значение меньше 3, поэтому его нельзя проанализировать и вернуть NaN.

Функция карты возвращает массив, поэтому окончательный результат будет [1, NaN, NaN].

Что такое анти-шейк и троттлинг? Какая разница? Как добиться?

Сложность: умеренная

Стабилизатор

Функция будет выполняться только один раз в течение n секунд после запуска высокочастотного события.Если высокочастотное событие будет запущено снова в течение n секунд, время будет пересчитано;

Идея: отменять предыдущий метод отложенного вызова каждый раз, когда срабатывает событие:

Нищее издание:

function debounce(fn) {
  let timeout = null; // 创建一个标记用来存放定时器的返回值
  return function () {
    clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
    timeout = setTimeout(() => { 
      // 然后又创建一个新的 setTimeout
      // 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
      fn.apply(this, arguments);
    }, 500);
  };
}
function sayHi() {
  console.log('防抖成功');
}

var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi)); // 防抖
дросселирование

События с высокой частотой запускаются, но выполняются только один раз в n секунд, поэтому регулирование снижает частоту выполнения функции.

Идея: каждый раз, когда запускается событие, определяйте, есть ли функция задержки, ожидающая выполнения.

Нищее издание:

function throttle(fn) {
  let canRun = true; // 通过闭包保存一个标记
  return function () {
    if (!canRun) return; // 在函数开头判断标记是否为 true,不为 true 则 return
    canRun = false; // 立即设置为 false
    setTimeout(() => { // 将外部传入的函数的执行放在 setTimeout 中
      fn.apply(this, arguments);
      // 最后在 setTimeout 执行完毕后再把标记设置为 true(关键) 表示可以执行下一次循环了
      // 当定时器没有执行的时候标记永远是 false,在开头被 return 掉
      canRun = true;
    }, 500);
  };
}
function sayHi(e) {
  console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(sayHi));

Покажите разницу между Set, Map, WeakSet и WeakMap?

Сложность: умеренная

Set

  • Элементы уникальны, неупорядочены и неповторяемы;
  • [значение, значение], значение ключа совпадает с именем ключа (или только значением ключа, без имени ключа);
  • Его можно обойти, методы: добавить, удалить, имеет.

WeakSet

  • члены являются объектами;
  • Члены являются слабыми ссылками, которые могут быть переработаны механизмом сборки мусора и могут использоваться для сохранения узлов DOM, что не так просто вызвать утечку памяти;
  • Его нельзя обойти.Методы включают в себя add, delete и has.

Map

  • По сути это набор пар ключ-значение, похожий на набор;
  • Его можно пройти, есть много методов, и его можно преобразовать с различными форматами данных.

WeakMap

  • Принимайте только объекты в качестве имен ключей (кроме null) и не принимайте другие типы значений в качестве имен ключей;
  • Имя ключа является слабой ссылкой, значение ключа может быть произвольным, объект, на который указывает имя ключа, может быть удален сборщиком мусора, а имя ключа в настоящее время недопустимо;
  • Его нельзя обойти.Методы включают get, set, has и delete.

Как реализовать обход в глубину и обход в ширину?

Сложность: умеренная

Обход в глубину (DFS)

Поиск в глубину — это тип алгоритма поиска, который просматривает узлы дерева по глубине дерева, ища ветви дерева как можно глубже. Когда все ребра узла v будут исследованы, вернитесь к начальному узлу того ребра, которое нашло узел v. Этот процесс продолжается до тех пор, пока исходный узел не будет исследован для всех других узлов.Если все еще есть необнаруженные узлы, выберите один из необнаруженных узлов в качестве исходного узла и повторяйте вышеуказанные операции, пока все узлы не будут исследованы.

Проще говоря, DFS должна отслеживать от узла в графе до последнего узла, затем выполнять обратную трассировку и продолжать отслеживать следующий путь, пока не будут достигнуты все узлы, и так далее, пока путь не исчезнет.

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

Примечание: Deep DFS — это слепой поиск, он не может гарантировать, что искомый путь является кратчайшим путем, и это не поиск определенного пути, а поиск путей на графе, которые можно выбрать при поиске.

шаг:

  • посетить вершину v;
  • Начиная с непосещенных соседних точек v по очереди, выполнять обход в глубину графа, пока не будут посещены вершины графа, имеющие путь с v;
  • Если на пути остаются непосещенные вершины, начиная с непосещенной вершины, обход в глубину выполняется снова, пока не будут посещены все вершины.

выполнить

Graph.prototype.dfs = function() {
   var marked = []
   for (var i=0; i<this.vertices.length; i++) {
       if (!marked[this.vertices[i]]) {
           dfsVisit(this.vertices[i])
       }
   }

   function dfsVisit(u) {
       let edges = this.edges
       marked[u] = true
       console.log(u)
       var neighbors = edges.get(u)
       for (var i=0; i<neighbors.length; i++) {
           var w = neighbors[i]
           if (!marked[w]) {
               dfsVisit(w)
           }
       }
   }
}
Обход в ширину (BFS)

Поиск в ширину начинается с корневого узла и пересекает узлы по ширине графа.Если все узлы были посещены, алгоритм завершает работу.BFS также является слепым поиском и обычно реализуется со структурой данных очереди.BFS .

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

шаг:

  • Создайте очередь и поместите начальный узел в очередь;
  • Если очередь не пуста, берем первый узел из очереди и проверяем, является ли он целевым узлом;
    • Если это целевой узел, завершить поиск и вернуть результат;
    • Если нет, добавьте в очередь все необнаруженные байты;
  • Если очередь пуста, что указывает на отсутствие целевого узла в графе, обход завершается.

выполнить

Graph.prototype.bfs = function(v) {
   var queue = [], marked = []
   marked[v] = true
   queue.push(v) // 添加到队尾
   while(queue.length > 0) {
       var s = queue.shift() // 从队首移除
       if (this.edges.has(s)) {
           console.log('visited vertex: ', s)
       }
       let neighbors = this.edges.get(s)
       for(let i=0;i<neighbors.length;i++) {
           var w = neighbors[i]
           if (!marked[w]) {
               marked[w] = true
               queue.push(w)
           }
       }
   }
}

Пожалуйста, напишите результат выполнения следующего кода:

Сложность: умеренная

async function async1() {
   console.log('async1 start')
   await async2()
   console.log('async1 end')
}
async function async2() {
   console.log('async2')
}
console.log('script start')
setTimeout(function () {
   console.log('settimeout')
})
async1()
new Promise(function (resolve) {
   console.log('promise1')
   resolve()
}).then(function () {
   console.log('promise2')
})
console.log('script end')

Суть темы в рассмотрении реализации и порядка выполнения setTimeout, promise и async await, а также вопросов, связанных с циклом событий JS.

Отвечать

script start
async1 start
async2
promise1
script end
async1 end
promise2
settimeout

Сгладьте массив и удалите повторяющиеся данные и, наконец, получите восходящий и неповторяющийся массив.

Сложность: умеренная

Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b})

История развития асинхронных решений JS, преимущества и недостатки

Сложность: умеренная

функция обратного вызова
setTimeout(() => {
   // callback 函数体
}, 1000)

Недостатки: ад обратных вызовов, невозможность отлова ошибок с помощью try catch, невозможность возврата

Фундаментальная проблема с callback hell:

  • Отсутствие последовательности: сложность отладки, вызванная адом обратных вызовов, несовместима с образом мышления мозга;
  • Вложенные функции связаны, и после их изменения они будут влиять на все тело, то есть (инверсия управления);
  • Слишком много вложенных функций и сложно обрабатывать ошибки.
ajax('XXX1', () => {
   // callback 函数体
   ajax('XXX2', () => {
       // callback 函数体
       ajax('XXX3', () => {
           // callback 函数体
       })
   })
})
Promise

Промис создан для решения проблемы обратного звонка.

Promise реализует цепные вызовы, что означает, что каждый раз после then возвращает новый Promise.Если мы вернемся в then, результат возврата будет обернут Promise.resolve().

Преимущество: решает проблему callback hell.

ajax('XXX1')
 .then(res => {
     // 操作逻辑
     return ajax('XXX2')
 }).then(res => {
     // 操作逻辑
     return ajax('XXX3')
 }).then(res => {
     // 操作逻辑
 })
Generator

Особенности: Он может контролировать выполнение функций и может использоваться с библиотекой функций co.js. (то есть библиотека, используемая коа в первые дни)

function *fetch() {
   yield ajax('XXX1', () => {})
   yield ajax('XXX2', () => {})
   yield ajax('XXX3', () => {})
}
let it = fetch()
let result1 = it.next()
let result2 = it.next()
let result3 = it.next()
Async/await

async, await — это идеальное решение проблемы асинхронности.

Плюсы: код понятен, и нет необходимости писать много потом цепочек наподобие промисов, что решает проблему callback hell;

Недостатки: await трансформирует асинхронный код в синхронный, если несколько асинхронных операций не имеют зависимостей, использование await приведет к падению производительности.

async function test() {
 // 以下代码没有依赖性的话,完全可以使用 Promise.all 的方式
 // 如果有依赖性的话,其实就是解决回调地狱的例子了
 await fetch('XXX1')
 await fetch('XXX2')
 await fetch('XXX3')
}

Вот пример использования await :

let a = 0
let b = async () => {
 a = a + await 10
 console.log('2', a) // -> '2' 10
}
b()
a++
console.log('1', a) // -> '1' 1

В приведенном выше объяснении упоминалось, что await реализует генератор внутри себя.На самом деле, await — это синтаксический сахар генератора плюс промис, а генератор автоматического выполнения реализован внутри. Если вы знакомы с co, вы можете реализовать такой синтаксический сахар самостоятельно.

Наконец

  1. Просто смотреть и не лайкать это хулиганство!!!
  2. Добро пожаловать, чтобы обратить внимание на общедоступную учетную запись «Продвинутый курс по интерфейсу», чтобы серьезно изучить интерфейс и продвигаться вместе.