Эта статья не является продвинутой технической статьей, она просто описывает процесс, с которым я недавно столкнулся, который заставил один из моих проектов ступить на яму из-за обновления Vue, и процесс, в котором я решил проблему. Хотя статья длинная, но не водянистая, цель ее написания — поделиться с вами методом и отношением к мышлению, когда я сталкиваюсь с проблемой.
Предыстория: В прошлом году я запустил вводный курс по Vue.js на MOOC.com —Приложение Ele.me на вынос с высокой имитацией Vue.js, этот курс получил очень хороший отклик, поэтому в этом году мы продолжили запуск продвинутого продвинутого практического курса Vue.js на онлайн-МООК.Музыкальное приложение Vue.js, тот же отзыв хороший. Каждый вечер, когда я возвращаюсь домой с работы, я иду в зону вопросов и ответов, чтобы просмотреть вопросы студентов. Я обнаружил, что многие студенты недавно задали один и тот же вопрос. Нажав на iOS, WeChat не может воспроизводить песни, но ПК могут . Обычно, когда я сталкиваюсь с такой проблемой, я сначала позволяю студентам посетить мой проект.онлайн-адрес, чтобы увидеть, нет ли проблем с моим кодом, и вывод, что мой онлайн-код в порядке, но они не могут его написать сами, и они говорят, что полностью сравнили с моим кодом, что заставляет меня чувствовать себя очень странно . Некоторым студентам не потребовалось много времени, чтобы найти способ привязать событие синхронного клика к глобальному документу и синхронно запустить метод воспроизведения звука в функции обратного вызова события клика. получил отзывы некоторых студентов.Принято, но моей первой реакцией после просмотра было то, что я не мог решить проблему таким хакерским способом, я должен был найти суть проблемы, поэтому я начал очень интересный процесс поиска проблема.
проблема позиционирования
Давайте сначала посмотрим на явление: код, написанный студентами, нельзя воспроизвести в браузере iOS WeChat, но на ПК все в порядке; код, который я написал онлайн, в порядке. Разобравшись с явлением, я приступил к устранению проблемы:
-
Есть ли проблема с кодом, написанным студентами?
Хотя такая возможность есть, она была отвергнута мной по двум параметрам: 1. Мои одноклассники тоже сравнили мой исходный код, и одноклассники, у которых есть проблемы, не изолированы; 2. Если это проблема с кодом, то скорее всего в том, что ни ПК, ни мобильный не могут играть. -
найти отличие?
Эта проблема появилась совсем недавно, когда студенты начали учиться писать код курса, они тоже инициализировали код через скаффолдинг vue-cli. Потом я взглянул на код инициализации новой версии скаффолдинга, и это действительно была большая разница.После обновления вебпака до 3+ конфигурация сильно изменилась. Однако, по моему опыту, обновление инструмента сборки не повлияет на бизнес-код, должны быть другие причины. -
Обновление Vue.js?
Помимо разницы в конфигурации веб-пакета, версия Vue.js, используемая для последнего кода инициализации скаффолдинга, — 2.5+, а версия Vue.js моего онлайн-кода — 2.3+.Может ли это быть проблемой, вызванной Vue.js? С этим вопросом я пошел читать Vue.jsrelease log, обнаружил, что Vue.js выпускался десятки раз в больших и малых версиях. Тщательная проверка каждого из них заняла бы очень много времени, поэтому я применил классический двухточечный метод для поиска. Сначала я обновил Vue.js до версии 2.4.0 и обнаружил, что его невозможно установить (это всего лишь .js я обновился до 2.4 npm (выпустил ошибку), поэтому я обновился до 2.4.1, а затем попробовал его на своем мобильном телефоне, и он все еще мог играть. Затем я обновил Vue.js до 2.5.0, и мобильный телефон не смог воспроизвести его после попытки (стереть...). Я медитировал в своем сердце и, наконец, нашел проблему.
характер проблемы
Мне потребовалось около получаса, чтобы найти проблему, описанную выше, но я не нашел основной причины проблемы, поэтому я прочитал Vue.js 2.5.release log, потому что это слишком долго перечислять. Каждое обновление Vue.js в основном делится на 2 категории: «Функции и улучшения» и «Исправление ошибок». Я просмотрел его сверху вниз, щелкнул некоторые изменения в его ядре, посмотрел на изменения в коде и, наконец, заблокировал это:
use MessageChannel for nextTick 6e41679, closes #6566 #6690
Потом я зашел и посмотрелизменять, опускаю небо, изменения очень большие, поменялась основная реализация nextTick, пропал MutationObserver, изменилась реализация MessageChannel. Подождите, некоторые ученики могут быть сбиты с толку, когда увидят это, о чем все это? Не волнуйтесь, позвольте мне кратко объяснить nextTick Vue.
nextTick
Прежде чем представить nextTick Vue, позвольте мне кратко представить механизм работы JS: выполнение JS является однопоточным и основано на цикле обработки событий. Для понимания цикла событий г-н РуанстатьяНаписание очень четкое, примерно разделенное на следующие этапы:
(1) Все задачи синхронизации выполняются в основном потоке, образуя стек контекста выполнения.
(2) В дополнение к основному потоку существует еще «очередь задач» (task queue). Как только асинхронная задача имеет запущенный результат, событие помещается в «очередь задач».
(3) Как только все задачи синхронизации в «стеке выполнения» будут выполнены, система прочитает «очередь задач», чтобы увидеть, какие события в ней находятся. Затем соответствующие асинхронные задачи завершают состояние ожидания, входят в стек выполнения и начинают выполнение.
(4) Основной поток продолжает повторять третий шаг выше.
Процесс выполнения основного потока — это тик, а все асинхронные результаты планируются и планируются через «очередь задач». Очередь сообщений хранит задачи одну за другой. В спецификации указано, что задачи делятся на две категории: макрозадачи и микрозадачи, и после завершения каждой макрозадачи все микрозадачи должны быть очищены.
Что касается понятий макрозадачи и микрозадачи, я не буду здесь вдаваться в подробности, а просто продемонстрирую порядок их выполнения через кусок кода:
for (macroTask of macroTaskQueue) {
// 1. Handle current MACRO-TASK
handleMacroTask();
// 2. Handle all MICRO-TASK
for (microTask of microTaskQueue) {
handleMicroTask(microTask);
}
}
В среде браузера общие макрозадачи включают setTimeout, MessageChannel, postMessage и setImmediate, а общие микрозадачи включают MutationObsever и Promise.then. Для получения дополнительной информации о них заинтересованные студенты могут прочитатьэта статья.
Возвращаясь к nextTick Vue, nextTick, как следует из названия, является следующим тиком.Vue реализует nextTick внутри и предоставляет его как глобальный API.Он поддерживает передачу функции обратного вызова, чтобы гарантировать, что время выполнения функции обратного галочка. Официальный документ веб-сайта представляет сценарии использования Vue.nextTick:
Использование: отложите выполнение обратного вызова после следующего цикла обновления DOM.Используйте его сразу после того, как вы изменили некоторые данные, чтобы дождаться обновления DOM.
Использование: выполнение отложенного обратного вызова после завершения следующего цикла обновления DOM. Используйте этот метод сразу после изменения данных, чтобы получить обновленный DOM.
В Vue.js это изменение представления, управляемое данными.Поскольку выполнение JS является однопоточным, оно может изменять данные несколько раз в течение тика, но Vue.js не настолько глуп, чтобы управлять данными каждый раз, когда они изменяются. изменения представления, он поместит все изменения данных в очередь, а затем внутренне вызовет nextTick для обновления представления, поэтому изменение данных в представлении DOM должно быть завершено в следующем такте.
Далее, давайте взглянем на реализацию nextTick Vue в версии Vue.js 2.5+, извлечем отдельныйnext-tick.jsфайл для его реализации.
/* @flow */
/* globals MessageChannel */
import { noop } from 'shared/util'
import { handleError } from './error'
import { isIOS, isNative } from './env'
const callbacks = []
let pending = false
function flushCallbacks () {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
// Here we have async deferring wrappers using both micro and macro tasks.
// In < 2.4 we used micro tasks everywhere, but there are some scenarios where
// micro tasks have too high a priority and fires in between supposedly
// sequential events (e.g. #4521, #6690) or even between bubbling of the same
// event (#6566). However, using macro tasks everywhere also has subtle problems
// when state is changed right before repaint (e.g. #6813, out-in transitions).
// Here we use micro task by default, but expose a way to force macro task when
// needed (e.g. in event handlers attached by v-on).
let microTimerFunc
let macroTimerFunc
let useMacroTask = false
// Determine (macro) Task defer implementation.
// Technically setImmediate should be the ideal choice, but it's only available
// in IE. The only polyfill that consistently queues the callback after all DOM
// events triggered in the same loop is by using MessageChannel.
/* istanbul ignore if */
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
macroTimerFunc = () => {
setImmediate(flushCallbacks)
}
} else if (typeof MessageChannel !== 'undefined' && (
isNative(MessageChannel) ||
// PhantomJS
MessageChannel.toString() === '[object MessageChannelConstructor]'
)) {
const channel = new MessageChannel()
const port = channel.port2
channel.port1.onmessage = flushCallbacks
macroTimerFunc = () => {
port.postMessage(1)
}
} else {
/* istanbul ignore next */
macroTimerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}
// Determine MicroTask defer implementation.
/* istanbul ignore next, $flow-disable-line */
if (typeof Promise !== 'undefined' && isNative(Promise)) {
const p = Promise.resolve()
microTimerFunc = () => {
p.then(flushCallbacks)
// in problematic UIWebViews, Promise.then doesn't completely break, but
// it can get stuck in a weird state where callbacks are pushed into the
// microtask queue but the queue isn't being flushed, until the browser
// needs to do some other work, e.g. handle a timer. Therefore we can
// "force" the microtask queue to be flushed by adding an empty timer.
if (isIOS) setTimeout(noop)
}
} else {
// fallback to macro
microTimerFunc = macroTimerFunc
}
/**
* Wrap a function so that if any code inside triggers state change,
* the changes are queued using a Task instead of a MicroTask.
*/
export function withMacroTask (fn: Function): Function {
return fn._withTask || (fn._withTask = function () {
useMacroTask = true
const res = fn.apply(null, arguments)
useMacroTask = false
return res
})
}
export function nextTick (cb?: Function, ctx?: Object) {
let _resolve
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx)
} catch (e) {
handleError(e, ctx, 'nextTick')
}
} else if (_resolve) {
_resolve(ctx)
}
})
if (!pending) {
pending = true
if (useMacroTask) {
macroTimerFunc()
} else {
microTimerFunc()
}
}
// $flow-disable-line
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}
После того, как у нас есть предыдущий фон знаний, нетрудно понять реализацию nextTick.Вот очень ключевое замечание: в версиях до Vue 2.4 nextTick почти всегда реализовывался на основе микрозадач, но поскольку выполнение микрозадач priorityized Уровень очень высокий, а в некоторых сценариях он даже быстрее, чем всплытие события, что приведет к некоторым странным проблемам, таким как проблема#4521,#6690,#6566; но если все изменить на макро-задачи, это также повлияет на производительность некоторых сцен с перерисовкой и анимацией, таких как проблема#6813. Итак, в конце концов, стратегия, принятая nextTick, состоит в том, чтобы взять микрозадачу по умолчанию.Для некоторых событий взаимодействия с DOM, таких как обработка функции обратного вызова события, связанной с v-on, макрозадача будет принудительно.
Как работает эта сила?Оказывается, когда Vue.js связывает события DOM, он по умолчанию выполняет обратный вызов.handler
вызов функцииwithMacroTask
Метод представляет собой слой упаковки, который гарантирует, что во время выполнения всей функции обратного вызова при изменении состояния данных эти изменения будут переданы задаче макроса.
Для выполнения макрозадач Vue.js сначала определяет, поддерживает ли он собственныеsetImmediate
, эта функция поддерживается только в более высоких версиях IE и Edge. Если она не поддерживается, проверьте, поддерживает ли она нативнуюMessageChannel
, если он не поддерживается, он будет понижен доsetTimeout 0
.
Влияние nextTick на воспроизведение звука
Возвращаясь к нашему вопросу, какое отношение это имеет к nextTick, если браузер iOS WeChat не может воспроизводить песни? Давайте посмотрим, как реализована наша функция воспроизведения песни.
В нашем коде будет компонент player.vue, в котором мы будем хранить аудиотег html5. Поскольку есть много мест, где можно вызвать воспроизведение, например компонент списка песен, компонент диаграммы, компонент результатов поиска и т. д., мы используем vuex для управления данными, связанными с воспроизведением. мы помещаем список воспроизведенияplaylist
и текущий индекс воспроизведенияcurrentIndex
Поддерживается с состоянием, в настоящее время воспроизводится песняcurrentSong
Из них рассчитываются:
// state.js
const state = {
playlist: [],
currentIndex:0
}
// getters.js
export const currentSong = (state) => {
return state.playlist[state.currentIndex] || {}
}
Затем смотрим в компоненте player.vuecurrentSong
Изменения в воспроизведении песни:
// player.vue
watch : {
currentSong(newSong,oldSong) {
if (!newSong.id || !newSong.url || newSong.id === oldSong.id) {
return
}
this.$refs.audio.src = newSong.url
this.$refs.audio.play()
}
}
Таким образом, мы можем отправить пару в любой компонентplaylist
иcurrentIndex
модификация для достижения цели воспроизведения разных песен. Так какое это имеет отношение к nextTick?
Потому что в Vue.js выполнение функции обратного вызова наблюдателя по умолчанию асинхронно.playlist
илиcurrenIndex
модификация вызоветcurrentSong
изменяется, но поскольку он асинхронный, функция обратного вызова наблюдателя не будет выполняться сразу, а будет выполняться после nextTick. Поэтому, когда мы нажимаем на песню в списке песен, функция обратного вызова события щелчка отправит паруplaylist
иcurrentIndex
После серии синхронных логических операций обратный вызов wathcer, наконец, выполняется после nextTick, то есть вызывается воспроизведение аудио.
Таким образом, по сути, воспроизведение, которое пользователь нажимает на звук, не завершается за тик, и процесс nextTick, выполняемый для события привязки v-on в Vue.js, упомянутого ранее, заставит использовать задачу макроса. Так это потому, что nextTick влияет на воспроизведение аудио в браузере iOS WeChat?
Давайте упростим сложность и напишем простую демонстрацию, чтобы проверить эту проблему.Используемая версия Vue.js — 2.5+.
<template>
<div id="app">
<audio ref="audio"></audio>
<button @click="changeUrl">click me</button>
</div>
</template>
<script>
const musicList = [
'http://ws.stream.qqmusic.qq.com/108756223.m4a?fromtag=46',
'http://ws.stream.qqmusic.qq.com/101787871.m4a?fromtag=46',
'http://ws.stream.qqmusic.qq.com/718475.m4a?fromtag=46'
]
export default {
name: 'app',
data() {
return {
index: 0,
url: ''
}
},
methods: {
changeUrl() {
this.index = (this.index + 1) % musicList.length
this.url = musicList[this.index]
}
},
watch: {
url(newUrl) {
this.$refs.audio.src = newUrl
this.$refs.audio.play()
}
}
}
</script>
Логика этого кода очень проста, мы добавим наблюдателя для мониторингаurl
изменить, при нажатии на кнопку будет вызыватьсяchangeUrl
метод, изменитьurl
, а затем выполняется функция обратного вызова наблюдателя и вызывается метод воспроизведения звука. Этот код может нормально воспроизводить песню в браузере ПК, но не может воспроизводиться в браузере iOS WeChat, что подтверждает нашу предыдущую догадку — функция обратного вызова события щелчка пользователя на воспроизведение аудио, если он испытал nextTick. Невозможно воспроизвести в браузере iOS WeChat.
Горшок для макро задачи?
Некоторые студенты могут подумать, что когда пользователь нажимает кнопку, чтобы запустить процесс воспроизведения, браузер iOS WeChat или браузер iOS Safari должны выполняться в одном и том же тике, так ли это необходимо? Мы делаем простую модификацию в приведенном выше коде:
changeUrl() {
this.index = (this.index + 1) % musicList.length
this.url = musicList[this.index]
setTimeout(()=>{
this.$refs.audio.src = this.url
this.$refs.audio.play()
}, 0)
}
Сейчас мы не используем nextTick Vue.js, мы напрямую моделируем процесс nextTick и обнаруживаем, что с помощьюsetTimeout 0
Его можно воспроизводить в браузере iOS WeChat, включая сафари iOS, но на самом деле мы можем играть до тех пор, пока время задержки находится в пределах 1000 мс, но более 1000 мс, напримерsetTimeout 1001
Я больше не могу в это играть. Заинтересованные студенты могут попробовать. Я не нашел теоретической основы для этого явления. Если вы знаете теорию, пожалуйста, оставьте сообщение и расскажите мне.
Итак, в результате вышеописанных экспериментов мы обнаружили, что нет необходимости выполнять воспроизведение в одном и том же тике, так почему следующий такт Vue.js невозможен? Вернемся к реализации макрозадачи nextTick, которая имеет приоритетsetImmediate
,ПотомMessageChannel
, и наконецsetTimeout 0
. Мы знаем, что помимо более высоких версий IE и Edge,setImmediate
Нет встроенной поддержки, если какой-либо инструмент не переписывает ее. иMessageChannel
Поддержка браузера по-прежнему очень высока, поэтому я изменил асинхронный процесс этой демонстрации, чтобы использоватьMessageChannel
выполнить.
changeUrl() {
this.index = (this.index + 1) % musicList.length
this.url = musicList[this.index]
let channel = new MessageChannel()
let port = channel.port2
channel.port1.onmessage = () => {
this.$refs.audio.src = this.url
this.$refs.audio.play()
}
port.postMessage(1)
}
Этот код можно воспроизвести в браузерах ПК, но нельзя воспроизвести в браузерах iOS WeChat.После отладки я обнаружил, чтоthis.$refs.audio.play()
Логика также может быть выполнена, но песня не может быть воспроизведена.Это должно быть ограничение браузера на использование MessageChannel для асинхронного воспроизведения звука.
Как упоминалось ранее, еще один способ реализовать задачу макроса — использовать postMessage, который также хорошо поддерживается браузерами.Давайте изменим демо, чтобы использовать его для его реализации.
changeUrl() {
this.index = (this.index + 1) % musicList.length
this.url = musicList[this.index]
addEventListener('message', () => {
this.$refs.audio.src = this.url
this.$refs.audio.play()
}, false);
postMessage(1, '*')
}
Этот код можно воспроизвести в браузерах ПК, браузерах iOS WeChat и iOS Safari, что указывает на то, что это не задача макросов, а горшки MessageChannel. На самом деле существует множество способов реализации макрозадач, заинтересованные студенты могут ознакомиться с несколькими макрозадачами в core-js.Метод реализации.
Как решить?
Теперь мы нашли суть проблемы, потому что MessageChannel используется преимущественно в nextTick Vue.js, что повлияет на воспроизведение браузера iOS WeChat, так как же мы можем решить эту проблему с минимальными затратами?
Понижение версии Vue.js
Если это реальный проект, работающий в производственной среде, нет сомнений, что это должно быть первым выбором для решения проблемы, потому что эта ошибка действительно вызвана обновлением Vue.js. В нашем реальном проекте мы все блокируем версию Vue.js, если только мы не хотим использовать функцию новой версии Vue.js или в текущей версии обнаружена серьезная ошибка, а новая версия была исправлена, мы обновляем Vue. js, и каждое обновление должно быть полностью функционально протестировано.
Почему понижение Vue.js до 2.4+ не проблема, потому что nextTick до Vue.js 2.5 сначала использует микрозадачи, поэтому время воспроизведения звука на самом деле все еще находится в текущем тике, поэтому, конечно, проблем не будет.
Когда дело доходит до проблем с версией, это на самом деле недостаток Vue.js. Иногда изменения слишком радикальны при обновлении версии. Например, обновление nextTick на этот раз на самом деле является очень основной функцией Vue.js, но это Только модульное тестирование не охватывает большое количество функциональных тестовых случаев, и его можно улучшить только с помощью сообщества и обратной связи.
Синхронизированный наблюдатель
Наблюдатель Vue.js по умолчанию является асинхронным.Конечно, он также предоставляет синхронный наблюдатель, так что выполнение функции обратного вызова наблюдателя не должно проходить через nextTick, что действительно может исправить эту ошибку, но вызовет другие проблемы. Поскольку в нашем музыкальном проигрывателе есть функция переключения режима воспроизведения во время воспроизведения, мы поддерживаем три режима воспроизведения: последовательное воспроизведение, случайное воспроизведение и одиночное циклическое воспроизведение. плейлистplaylist
модифицированный, модифицированныйcurrentIndex
, что гарантирует, что мы не изменим текущую песню при переключении режимов. Затем возникает проблема, потому чтоcurrentSong
Отplaylist
иcurrentIndex
Рассчитано, любая их модификация вызовет срабатываниеcurrentSong
Поскольку теперь мы переходим на синхронный наблюдатель, обратный вызов currentSong будет выполнен дважды, поэтому первая модификация приводит к тому, что рассчитанная песня становится другой песней, что, очевидно, не соответствует нашим ожиданиям. Таким образом, синхронизация наблюдателей также невозможна.
другой путь
На самом деле, есть много способов «исправить» эту проблему, например, вместо использования наблюдателя мы можем изменить его, чтобы он уведомлял о каждом клике по шине событий, например, мы по-прежнему используем синхронный наблюдатель, но currentSong делает это. не проходит вычисление и напрямую зарезервировано с состоянием; например, каждый раз, когда событие click не привязано к v-on, мы напрямую используем собственный addEventListener в смонтированной функции хука для привязки события click.
Конечно, вышеперечисленные методы все осуществимы, но я не рекомендую менять их таким образом, потому что изменения в бизнес-коде слишком велики.Если наш собственный метод написания разумен, мы должны принудительно перейти на эти методы. типа: я знаю некую яму в фреймворке, и использую какие-то уловки, чтобы эти ямы обойти, что неразумно.
В чем значение фреймворка: сформулировать удобную спецификацию разработки, повысить эффективность разработки и позволить разработчикам больше сосредоточиться на разработке бизнес-логики. Поэтому отличный фреймворк не должен ограничивать способ реализации функций разработчиками в некоторых сценариях только потому, что этот метод реализации, хотя и разумный сам по себе, может спровоцировать некую яму во фреймворке.
Временный способ взлома
Поскольку я не хотел трогать бизнес-код, я подумал о некоторых методах взлома.Поскольку это горшок MessageChannel, я представил hack.js перед инициализацией Vue.js.
// hack for global nextTick
function noop() {
}
window.MessageChannel = noop
window.setImmediate = noop
В этом случае, когда Vue.js инициализирует nextTick, он находит глобальныйsetImmediate
иMessageChannel
перезаписывается, он автоматически понижается доsetTimeout 0
реализации, так что мы можем избежать нашей проблемы. Конечно, этот вид взлома не представляет никакой сложности, и я не рекомендую его.
Сообщить о проблеме для Vue.js
Поэтому самое разумное в этой ситуации — поднять вопрос для Vue.js, что я и сделал, и поднял вопрос на Github.issue, впервые поднимая проблему для Vue.js, я обнаружил, что официальная работа Vue все еще очень гуманизирована, поэтому я напрямую поднимаю проблему перед эмитентом.Ссылка на сайт, опишите проблему, заполнив несколько форм, и порекомендуйте хороший инструмент для воспроизведения проблемыCodeSandbox. В тот же день на этот вопрос был получен ответ от You Da.Он сказал, что nextTick Vue.js действительно вызовет эту проблему, но я должен закончить воспроизведение песни в том же тике, а не использовать наблюдатель, а затем я закрыл проблема. Поскольку я поднял этот вопрос, чтобы продемонстрировать основную проблему более интуитивно, я использовал очень простую демонстрацию, упомянутую выше, поэтому в этом сценарии то, что он сказал, не проблема, действительно нет необходимости использовать наблюдатель, поэтому я быстро ответил еще раз. issue, который объясняет мой реальный сценарий использования и показывает, что я надеюсь решить эту проблему из ядра Vue.js. К сожалению, You Da еще не ответил на этот вопрос.
Суммировать
Записывая на этот раз процесс поиска проблемы — локализации проблемы — решения проблемы, я хочу, чтобы учащиеся задумались не только о самой проблеме, но и о некоторых наших отношениях после того, как они столкнулись с проблемой. Найти проблемы несложно. Многие люди находят проблемы при написании кода. После обнаружения проблемы ваша первая реакция — попытаться решить ее самостоятельно или обратиться за помощью. Я считаю, что первое определенно лучше. Затем нам нужно найти проблему, прежде чем решать ее. Здесь я хочу упомянуть слово, называемое «программирование, ориентированное на совпадения». Многие люди будут продолжать пробовать этот метод после того, как столкнутся с проблемой. Весьма вероятно, что определенный метод «решит проблему». "эта проблема на первый взгляд. Проблемы, но не знаю почему, такой способ решения проблем очень ненадежен, вы можете не решить проблему принципиально, или вы можете решить эту проблему, но вызвать другую проблему. Поэтому определение сути проблемы очень важно. На самом деле это способность. Хороший инженер может не только писать код, но и проверять проблемы. Умение быстро найти суть проблемы является необходимым условием для отличный инженер.Это непросто, требует постоянного накопления. После обнаружения сути проблемы необходимо решить проблему.Часто у проблемы есть несколько решений, но разумно ли каждое решение - это тоже процесс, который нужно учитывать, общаться с некоторыми людьми, которые лучше вас , и накапливать больше Это тоже кумулятивный процесс. Если вы столкнетесь с проблемами в будущем и столкнетесь с ними с таким отношением, то вы быстро повзрослеете.
После изучения моего музыкального курса многие студенты будут спрашивать: «Господин Хуанг, когда вы выпустите новый клип?» Собственно, я хочу сказать, вы действительно закончили этот курс? Поскольку его позиционирование является продвинутым курсом Vue.js, не только потому, что сам курсовой проект более сложен, но и многие точки знаний в проекте могут быть расширены, и в проекте неизбежно будут небольшие ошибки, а некоторые из-за In в случае недоступности функций, вызванных изменениями интерфейса, помимо того, что у меня возникают вопросы, попробуйте решить их самостоятельно, а затем отправьте мне пулл-реквесты, мне так лучше? Так что этот курс стоит изучить больше. Если вы действительно истощите ценность этого курса, еще не поздно спросить меня снова. Конечно, я также принесу вам больше курсов.
Наконец, давайте перейдем к моему продвинутому курсу Vue.js от Amway (Адрес МООК), заинтересованные студенты могут щелкнуть, чтобы просмотреть введение в курс. Проект курса размещен на моем частном сервере Github и не является открытым исходным кодом, поэтому весь код, связанный с этим курсом снаружи, является пиратским. Я поддерживал этот исходный код, включая недавнее обновление каркаса Vue.js и недоступность функций, вызванную некоторыми преобразованиями интерфейса проверяющей стороны, которые были устранены. Просто сделайте несколько скриншотов:
Этот посвящен вопросам.Мы решили десятки вопросов после запуска курса.Если у студентов возникнут проблемы в процессе обучения, рекомендуется прочитать вопросы, чтобы найти ответы. Есть некоторые проблемы с обновлением версии, которые я не буду закрывать, чтобы учащимся было легче их найти.
Это запись о представлении кода.Видно, что кроме меня есть несколько очень хороших одноклассников, которые вместе поддерживают этот проект.Среди них один одноклассник очень активен в обучении и обладает сильной самостоятельной силой.Он часто обсуждает технические проблемы со мной Недавно он Мы также присоединились к Didi и сделали много выводов в нашем отделе.
Чтобы почувствовать этот проект более интуитивно, вы можете отсканировать QR-код ниже, чтобы испытать ощущение, близкое к нативному приложению:
У нас есть официальная группа обмена курсами. Если вы купите этот курс, вы можете обмениваться и учиться с другими студентами. Вы также можете добавить мои qq и WeChat, и вы можете задавать вопросы о коммуникационных технологиях, но я обычно занят во время днем и есть только ночью.
Конечно, если вы хотите следить за некоторыми моими новостями, вы также можете подписаться на меня.Github.
Я надеюсь, что студенты будут поддерживать подлинные издания и сопротивляться пиратству. Я предложу вам больше высококачественных курсов и других форм технического обмена.
Некоторые статьи, достойные расширенного изучения, упомянутые в этой статье:
Подробное объяснение механизма работы JavaScript: снова поговорим о цикле событий