JavaScript —从回调到异步/等待

JavaScript is synchronous. This means that it will execute your code block by order after hoisting. Before the code executes, var and function declarations are “hoisted” to the top of their scope.

JavaScript是同步的。 这意味着它将在提升后按顺序执行代码块。 在代码执行之前,将varfunction声明“提升”到其作用域的顶部。

This is an example of a synchronous code:

这是一个同步代码的示例:

console.log('1')console.log('2')console.log('3')

This code will reliably log “1 2 3".

此代码将可靠地记录为“ 1 2 3”。

Asynchronous requests will wait for a timer to finish or a request to respond while the rest of the code continues to execute. Then when the time is right a callback will spring these asynchronous requests into action.

异步请求将等待计时器完成或请求响应,而其余代码将继续执行。 然后,当时间合适时, 回调将使这些异步请求生效。

This is an example of an asynchronous code:

这是一个异步代码的示例:

console.log('1')setTimeout(function afterTwoSeconds() {console.log('2')
}, 2000)console.log('3')

This will actually log “1 3 2”, since the “2” is on a setTimeout which will only execute, by this example, after two seconds. Your application does not hang waiting for the two seconds to finish. Instead it keeps executing the rest of the code and when the timeout is finished it returns to afterTwoSeconds.

实际上,这将记录为“ 1 3 2”,因为“ 2”位于setTimeout上,在此示例中,仅在两秒钟后执行。 您的应用程序不会挂起等待两秒钟。 相反,它将继续执行其余代码,并且当超时完成时,它将返回至afterTwoSeconds。

You may ask “Why is this useful?” or “How do I get my async code to become sync?”. Hopefully I can show you the answers.

您可能会问“为什么这有用?” 或“如何使我的异步代码变得同步?”。 希望我能给你答案。

“问题” (“The problem”)

Let us say our goal is to search for a GitHub user and get all the repositories of that user. The thing is we don’t know the exact name of the user. So we have to list all the users with similar name and their respective repositories.

让我们说我们的目标是搜索GitHub用户并获取该用户的所有存储库。 问题是我们不知道用户的确切名称。 因此,我们必须列出名称相似的所有用户及其各自的存储库。

Doesn’t need to super fancy, something like this

不需要花哨的东西,像这样

In these examples the request code will use XHR (XMLHttpRequest). You can replace it with jQuery $.ajax or the more recent native approach called fetch. Both will give you the promises approach out of the gate.

在这些示例中,请求代码将使用XHR( XMLHttpRequest )。 您可以将其替换为jQuery $.ajax或较新的本地方法fetch 。 两者都会使您脱颖而出。

It will be slightly changed depending on your approach but as a starter:

首先,它会根据您的方法稍有变化:

// url argument can be something like 'https://api.github.com/users/daspinola/repos'function request(url) {const xhr = new XMLHttpRequest();xhr.timeout = 2000;xhr.onreadystatechange = function(e) {if (xhr.readyState === 4) {if (xhr.status === 200) {// Code here for the server answer when successful} else {// Code here for the server answer when not successful}}}xhr.ontimeout = function () {// Well, it took to long do some code here to handle that}xhr.open('get', url, true)xhr.send();
}

Remember that in these examples the important part is not what the end result of the code is. Instead your goal should be to understand the differences of the approaches and how you can leverage them for your development.

请记住,在这些示例中,重要的部分不是代码的最终结果。 相反,您的目标应该是了解方法的差异以及如何利用它们进行开发。

打回来 (Callback)

You can save a reference of a function in a variable when using JavaScript. Then you can use them as arguments of another function to execute later. This is our “callback”.

使用JavaScript时,可以将函数的引用保存在变量中。 然后,您可以将它们用作另一个函数的参数,以便以后执行。 这是我们的“回调”。

One example would be:

一个例子是:

// Execute the function "doThis" with another function as parameter, in this case "andThenThis". doThis will execute whatever code it has and when it finishes it should have "andThenThis" being executed.doThis(andThenThis)// Inside of "doThis" it's referenced as "callback" which is just a variable that is holding the reference to this functionfunction andThenThis() {console.log('and then this')
}// You can name it whatever you want, "callback" is common approachfunction doThis(callback) {console.log('this first')// the '()' is when you are telling your code to execute the function reference else it will just log the referencecallback()
}

Using the callback to solve our problem allows us to do something like this to the request function we defined earlier:

使用callback来解决我们的问题,使我们可以对之前定义的request函数执行以下操作:

function request(url, callback) {const xhr = new XMLHttpRequest();xhr.timeout = 2000;xhr.onreadystatechange = function(e) {if (xhr.readyState === 4) {if (xhr.status === 200) {callback(null, xhr.response)} else {callback(xhr.status, null)}}}xhr.ontimeout = function () {console.log('Timeout')}xhr.open('get', url, true)xhr.send();
}

Our function for the request will now accept a callback so that when a request is made it will be called in case of error and in case of success.

现在,我们用于请求的函数将接受callback以便在发出request时将在错误和成功的情况下调用它。

const userGet = `https://api.github.com/search/users?page=1&q=daspinola&type=Users`request(userGet, function handleUsersList(error, users) {if (error) throw errorconst list = JSON.parse(users).itemslist.forEach(function(user) {request(user.repos_url, function handleReposList(err, repos) {if (err) throw err// Handle the repositories list here})})
})

Breaking this down:

分解如下:

  • We make a request to get a user’s repositories

    我们请求获取用户的存储库
  • After the request is complete we use callback handleUsersList

    请求完成后,我们使用回调handleUsersList

  • If there is no error then we parse our server response into an object using JSON.parse

    如果没有错误,则使用JSON.parse服务器响应解析为一个对象

  • Then we iterate our user list since it can have more than one

    然后,我们迭代用户列表,因为它可以有多个

    For each user we request their repositories list.

    对于每个用户,我们都请求他们的存储库列表。

    We will use the url that returned per user in our first response

    我们将在第一个响应中使用每个用户返回的网址

    We call

    我们称之为

    repos_urlas the url for our next requests or from the first response

    repos_url作为下一个请求或第一个响应的URL

  • When the request has completed the callback, we will call

    当请求完成回调后,我们将调用

    This will handle either its error or the response with the list of repositories for that user

    这将使用该用户的存储库列表来处理其错误或响应

Note: Sending the error first as parameter is a common practice especially when using Node.js.

注意 :通常首先发送错误作为参数,尤其是在使用Node.js时。

A more “complete” and readable approach would be to have some error handling. We would keep the callback separate from the request execution.

一种更“完整”且易读的方法是要进行一些错误处理。 我们将使回调与请求执行分开。

Something like this:

像这样:

try {request(userGet, handleUsersList)
} catch (e) {console.error('Request boom! ', e)
}function handleUsersList(error, users) {if (error) throw errorconst list = JSON.parse(users).itemslist.forEach(function(user) {request(user.repos_url, handleReposList)})
}function handleReposList(err, repos) {if (err) throw err// Handle the repositories list hereconsole.log('My very few repos', repos)
}

This ends up having problems like racing and error handling issues. Racing happens when you don’t control which user you will get first. We are requesting the information for all of them in case there is more than one. We are not taking an order into account. For example, user 10 can come first and user 2 last. We have a possible solution later in the article.

最终会出现竞速和错误处理问题。 当您无法控制将首先获得哪个用户时,就会发生竞速。 如果不止一个,我们要求提供所有这些信息。 我们没有考虑订单。 例如,用户10可以排在第一位,而用户2可以排在最后。 我们将在本文后面提供一个可能的解决方案。

The main problem with callbacks is that maintenance and readability can become a pain. It sort of already is and the code does hardly anything. This is known as callback hell which can be avoided with our next approach.

回调的主要问题是维护和可读性会变得很痛苦。 它已经存在,并且代码几乎没有任何作用。 这被称为回调地狱 ,可以通过我们的下一种方法来避免。

承诺 (Promises)

Promises you can make your code more readable. A new developer can come to the code base and see a clear order of execution to your code.

保证您可以使代码更具可读性。 新的开发人员可以进入代码库,并查看代码的清晰执行顺序。

To create a promise you can use:

要创建承诺,您可以使用:

const myPromise = new Promise(function(resolve, reject) {// code hereif (codeIsFine) {resolve('fine')} else {reject('error')}})myPromise.then(function whenOk(response) {console.log(response)return response}).catch(function notOk(err) {console.error(err)})

Let us decompose it:

让我们分解一下:

  • A promise is initialized with a function that has resolve and reject statements

    使用具有resolvereject语句的function初始化promise

  • Make your async code inside the Promise function

    使您的异步代码在Promise函数中

    Make your async code inside the Promise functionresolve when everything happens as desired

    当一切都按需进行时,使Promise函数中的异步代码Promise resolve

    Otherwise

    除此以外

    reject

    reject

  • When a resolve is found the .then method will execute for that Promise

    找到resolve.then方法将针对该Promise执行

    When a

    当一个

    reject is found the .catch will be triggered

    发现reject ,将触发.catch

Things to bear in mind:

注意事项:

  • resolve and reject only accept one parameter

    resolvereject仅接受一个参数

    resolve and reject only accept one parameterresolve(‘yey’, ‘works’) will only send ‘yey’ to the .then callback function

    resolvereject只接受一个参数resolve('yey', 'works')将只发送“yey”到.then回调函数

  • If you chain multiple .then

    如果链接多个.then

    Add a

    添加一个

    return if you want the next .then value not to be undefined

    return如果你想下一个.then值不被undefined

  • When a reject is caught with .catch if you have a .then chained to it

    当一个reject被抓到.catch如果你有一个.then链接到它

    It will still execute that

    它仍然会执行

    .then

    .then

    You can see the

    你可以看到

    .then as an “always executes” and you can check an example in this comment

    .then作为“始终执行”,您可以在此注释中查看示例

  • With a chain on .then if an error happens on the first one

    如果链上.then如果第一个发生错误

    It will skip subsequent

    随后将跳过

    .then until it finds a .catch

    .then ,直到找到一个.catch

  • A promise has three states

    一个承诺有三个状态

    A promise has three statespending

    一个承诺有三个待处理状态

  • When waiting for a resolve or reject to happen

    等待resolvereject发生时

    When waiting for a resolve or reject to happenresolved

    当等待resolvereject发生解决时

    When waiting for a resolve or reject to happenresolved rejected

    在等待resolvereject发生时, 解决 被拒绝

  • Once it’s in a resolved or rejected state

    一旦处于已resolved或已rejected状态

    It cannot be changed

    不能改变

Note: You can create promises without the function at the moment of declarations. The way that I’m showing it is only a common way of doing it.

注意 :在声明时,您可以创建没有功能的promise。 我展示它的方式只是这样做的一种常见方式。

“Theory, theory, theory…I’m confused” you may say.

您可能会说:“理论,理论,理论……我很困惑”。

Let’s use our request example with a promise to try to clear things up:

让我们将请求示例与一个承诺一起使用来尝试清除问题:

function request(url) {return new Promise(function (resolve, reject) {const xhr = new XMLHttpRequest();xhr.timeout = 2000;xhr.onreadystatechange = function(e) {if (xhr.readyState === 4) {if (xhr.status === 200) {resolve(xhr.response)} else {reject(xhr.status)}}}xhr.ontimeout = function () {reject('timeout')}xhr.open('get', url, true)xhr.send();})
}

In this scenario when you execute request it will return something like this:

在这种情况下,当您执行request ,它将返回如下内容:

const userGet = `https://api.github.com/search/users?page=1&q=daspinola&type=Users`const myPromise = request(userGet)console.log('will be pending when logged', myPromise)myPromise.then(function handleUsersList(users) {console.log('when resolve is found it comes here with the response, in this case users ', users)const list = JSON.parse(users).itemsreturn Promise.all(list.map(function(user) {return request(user.repos_url)}))}).then(function handleReposList(repos) {console.log('All users repos in an array', repos)}).catch(function handleErrors(error) {console.log('when a reject is executed it will come here ignoring the then statement ', error)})

This is how we solve racing and some of the error handling problems. The code is still a bit convoluted. But its a way to show you that this approach can also create readability problems.

这就是我们解决赛车以及一些错误处理问题的方式。 代码仍然有些复杂。 但是,这是一种向您展示这种方法还会造成可读性问题的方法。

A quick fix would be to separate the callbacks like so:

一个快速的解决方法是像这样将回调分开:

const userGet = `https://api.github.com/search/users?page=1&q=daspinola&type=Users`const userRequest = request(userGet)// Just by reading this part out loud you have a good idea of what the code does
userRequest.then(handleUsersList).then(repoRequest).then(handleReposList).catch(handleErrors)function handleUsersList(users) {return JSON.parse(users).items
}function repoRequest(users) {return Promise.all(users.map(function(user) {return request(user.repos_url)}))
}function handleReposList(repos) {console.log('All users repos in an array', repos)
}function handleErrors(error) {console.error('Something went wrong ', error)
}

By looking at what userRequest is waiting in order with the .then you can get a sense of what we expect of this code block. Everything is more or less separated by responsibility.

通过查看与userRequest等待的userRequest .then您可以了解我们对这个代码块的期望。 一切或多或少都由责任分隔。

This is “scratching the surface” of what Promises are. To have a great insight on how they work I cannot recommend enough this article.

这就是“承诺”的“表面”。 要对它们的工作原理有一个深刻的了解,我不能推荐这篇文章 。

发电机 (Generators)

Another approach is to use the generators. This is a bit more advance so if you are starting out feel free to jump to the next topic.

另一种方法是使用发电机。 这还有一些进步,因此,如果您刚开始,请随时跳到下一个主题。

One use for generators is that they allow you to have async code looking like sync.

生成器的一种用途是,它们使您可以拥有看起来像同步的异步代码。

They are represented by a * in a function and look something like:

它们在函数中由*表示,外观类似于:

function* foo() {yield 1const args = yield 2console.log(args)
}
var fooIterator = foo()console.log(fooIterator.next().value) // will log 1
console.log(fooIterator.next().value) // will log 2fooIterator.next('aParam') // will log the console.log inside the generator 'aParam'

Instead of returning with a return, generators have a yield statement. It stops the function execution until a .next is made for that function iteration. It is similar to .then promise that only executes when resolved comes back.

生成器具有yield语句,而不是返回return 。 它会停止函数执行,直到为该函数迭代创建.next为止。 它类似于.then承诺,仅在解决方案返回时才执行。

Our request function would look like this:

我们的请求函数如下所示:

function request(url) {return function(callback) {const xhr = new XMLHttpRequest();xhr.onreadystatechange = function(e) {if (xhr.readyState === 4) {if (xhr.status === 200) {callback(null, xhr.response)} else {callback(xhr.status, null)}}}xhr.ontimeout = function () {console.log('timeout')}xhr.open('get', url, true)xhr.send()}
}

We want to have the url as an argument. But instead of executing the request out of the gate we want it only when we have a callback to handle the response.

我们希望将url作为参数。 但是,仅当我们具有处理响应的回调时,我们才需要它,而不是从门外执行请求。

Our generator would be something like:

我们的generator将是这样的:

function* list() {const userGet = `https://api.github.com/search/users?page=1&q=daspinola&type=Users`const users = yield request(userGet)yieldfor (let i = 0; i<=users.length; i++) {yield request(users[i].repos_url)}
}

It will:

它会:

  • Wait until the first request is prepared

    等到第一个request准备好

  • Return a function reference expecting a callback for the first request

    返回一个function引用,期望第一个requestcallback

    Our

    我们的

    request function accepts a url

    request函数接受url

    and returns a

    并返回一个

    function that expects a callback

    需要callback function

  • Expect a users to be sent in the next .next

    期望在下一个.next发送users

  • Iterate over users

    遍历users

  • Wait for a .next for each of the users

    等待每个users.next

  • Return their respective callback function

    返回各自的回调函数

So an execution of this would be:

因此,将执行以下操作:

try {const iterator = list()iterator.next().value(function handleUsersList(err, users) {if (err) throw errconst list = JSON.parse(users).items// send the list of users for the iteratoriterator.next(list)list.forEach(function(user) {iterator.next().value(function userRepos(error, repos) {if (error) throw repos// Handle each individual user repo hereconsole.log(user, JSON.parse(repos))})})})  
} catch (e) {console.error(e)
}

We could separate the callback functions like we did previously. You get the deal by now, a takeaway is that we now can handle each individual user repository list individually.

我们可以像以前一样分离回调函数。 您现在就达成了交易,一个收获是,我们现在可以分别处理每个单独的用户存储库列表。

I have mixed felling about generators. On one hand I can get a grasp of what is expected of the code by looking at the generator.

我对发电机一无所知。 一方面,通过查看生成器,我可以了解代码的期望。

But its execution ends up having similar problems to the callback hell.

但是其执行最终会遇到与回调地狱类似的问题。

Like async/await, a compiler is recommended. This is because it isn’t supported in older browser versions.

与async / await一样 ,建议使用编译器。 这是因为较旧的浏览器版本不支持该功能。

Also it isn’t that common in my experience. So it may generate confusing in codebases maintained by various developers.

根据我的经验,这也不是那么普遍。 因此,它可能会在由各种开发人员维护的代码库中引起混乱。

An awesome insight of how generators work can be found in this article. And here is another great resource.

在本文中可以找到有关生成器工作原理的真知灼见。 这是另一个很棒的资源 。

异步/等待 (Async/Await)

This method seems like a mix of generators with promises. You just have to tell your code what functions are to be async. And what part of the code will have to await for that promise to finish.

这种方法似乎是带有承诺的生成器的混合体。 您只需要告诉您的代码哪些函数将是async 。 以及代码的哪一部分必须awaitpromise完成。

sumTwentyAfterTwoSeconds(10).then(result => console.log('after 2 seconds', result))async function sumTwentyAfterTwoSeconds(value) {const remainder = afterTwoSeconds(20)return value + await remainder
}function afterTwoSeconds(value) {return new Promise(resolve => {setTimeout(() => { resolve(value) }, 2000);});
}

In this scenario:

在这种情况下:

  • We have sumTwentyAfterTwoSeconds as being an async function

    我们将sumTwentyAfterTwoSeconds作为异步函数

  • We tell our code to wait for the resolve or reject for our promise function afterTwoSeconds

    afterTwoSeconds我们告诉我们的代码等待我们的promise函数的resolvereject

  • It will only end up in the .then when the await operations finish

    它只会在await操作结束时以.then结尾

    In this case there is only one

    在这种情况下,只有一个

Applying this to our request we leave it as a promise as seen earlier:

将此应用于我们的request我们将其作为一个promise如先前所示:

function request(url) {return new Promise(function(resolve, reject) {const xhr = new XMLHttpRequest();xhr.onreadystatechange = function(e) {if (xhr.readyState === 4) {if (xhr.status === 200) {resolve(xhr.response)} else {reject(xhr.status)}}}xhr.ontimeout = function () {reject('timeout')}xhr.open('get', url, true)xhr.send()})
}

We create our async function with the needed awaits like so:

我们使用所需的等待创建async函数,如下所示:

async function list() {const userGet = `https://api.github.com/search/users?page=1&q=daspinola&type=Users`const users = await request(userGet)const usersList = JSON.parse(users).itemsusersList.forEach(async function (user) {const repos = await request(user.repos_url)handleRepoList(user, repos)})
}function handleRepoList(user, repos) {const userRepos = JSON.parse(repos)// Handle each individual user repo hereconsole.log(user, userRepos)
}

So now we have an async list function that will handle the requests. Another async is needed in the forEach so that we have the list of repos for each user to manipulate.

因此,现在我们有了一个异步list函数来处理请求。 forEach需要另一个异步,以便我们拥有供每个用户操纵的存储repos列表。

We call it as:

我们称其为:

list().catch(e => console.error(e))

This and the promises approach are my favorites since the code is easy to read and change. You can read about async/await more in depth here.

由于易于阅读和更改代码,因此我最喜欢这种方法和Promise方法。 您可以在此处详细了解异步/等待。

A downside of using async/await is that it isn’t supported in the front-end by older browsers or in the back-end. You have to use the Node 8.

使用async / await的缺点是旧版浏览器或后端不支持它的前端。 您必须使用节点8。

You can use a compiler like babel to help solve that.

您可以使用像babel这样的编译器来解决这个问题。

“解” (“Solution”)

You can see the end code accomplishing our initial goal using async/await in this snippet.

您可以在此代码段中看到使用async / await完成我们最初目标的最终代码 。

A good thing to do is to try it yourself in the various forms referenced in this article.

要做的一件好事是以本文引用的各种形式自己尝试。

结论 (Conclusion)

Depending on the scenario you might find yourself using:

根据情况,您可能会发现自己使用:

  • async/await

    异步/等待
  • callbacks

    回叫
  • mix

    混合

It’s up to you what fits your purposes. And what lets you maintain the code so that it is understandable to others and your future self.

取决于您的目的。 什么使您能够维护代码,以便他人和您将来的自己可以理解。

Note: Any of the approaches become slightly less verbose when using the alternatives for requests like $.ajax and fetch.

注意:当对$.ajaxfetch类的请求使用替代方法时,任何一种方法的冗长程度都会略微降低。

Let me know what you would do different and different ways you found to make each approach more readable.

让我知道您会采取什么不同的方式来发现每种方法,以使其更具可读性。

This is Article 11 of 30. It is part of a project for publishing an article at least once a week, from idle thoughts to tutorials. Leave a comment, follow me on Diogo Spínola and then go back to your brilliant project!

这是30条中的第11条。它是一个项目的一部分,该项目每周至少发表一次文章,从无聊的想法到教程。 发表评论,关注我DiogoSpínola ,然后回到您的杰出项目!

翻译自: https://www.freecodecamp.org/news/javascript-from-callbacks-to-async-await-1cc090ddad99/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/395310.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于解决工作中的自动化环境搭建的解决方案(序)

时间&#xff1a;2015~2017 之前的自动化搭建平台&#xff1a;robotest 安装工具&#xff1a;jdk1.8,robotest 这种工具反正超级好用&#xff0c;华为方搞得工具&#xff0c;前台操作超级傻瓜。会点xpatch&#xff0c;一些东西根本不在话下。但是坑爹的就是&#xff0c;出了外包…

xshell安装mysql步骤_mysql主从复制

前期提要&#xff1a;三年前双11买的阿里云今年到期了&#xff0c;win2012的&#xff0c;上面mysql数据库里记着自己的一些记账数据&#xff0c;上一年双11买了腾讯云的&#xff0c;centos7.7, 想学学MYSQL的复制功能&#xff0c;今天趁着无BUG可撸&#xff0c;试着配置了一下&…

大专学计算机维修,《计算机维修与网络工程》大专学历班

语文、数学、计算机英语、公文写作等办公自动化指法训练、英文打字、智能拼音及高速五笔字型中文打字、windows操作、Word2003文字处理软件、Excel2003电子表格、Powerpoint2003幻灯片制作、Internet网络的上网方法、浏览、下载、电子邮件收发等。本班学习完毕&#xff0c;可独…

webpack指定第三方模块的查找路径

通常我们会使用一些地方模块在我们的项目中&#xff0c;比如bootstrap import bootstrap 导入的bootstrap默认会查找当前目录的node_modules文件&#xff0c;但是如果这个文件没有&#xff0c;会依次往上级模块查找&#xff0c;直到到C盘的根目录为止&#xff0c;可以通过webpa…

我的第一个安卓应用程序_我如何设计我的第一个应用程序

我的第一个安卓应用程序by Daniel Novykov丹尼尔诺维科夫(Daniel Novykov) 我如何设计我的第一个应用程序 (How I Designed My First App) This is a story about building a product, what went wrong, and how it changed my career into Design.这是一个有关构建产品&#…

Appium——主从控制执行

1.客户端(Eclipse)机器A&#xff0c; 服务端(appium、Genymotion)机器B 2.设置Appium&#xff0c;Server Address为192.168.17.123&#xff0c;重新启动Appium 3.在客户端机器A浏览器中输入&#xff1a;http://192.168.17.123:4723/wd/hub&#xff0c; 说明配置成功。 JAVA代码…

Python学习-03(集合,文件,编码)

上周复习&#xff1a; 列表增删改查 元祖是可读列表 字符串操作 字典是无序的&#xff0c;通过key来找值。字典可以嵌套列表和字典 本周内容&#xff1a;集合--文件---字符编码 集合引入&#xff1a; #随机生成20个小于20的数&#xff0c;输出所有的数&#xff0c;# 要求重复…

安装centos7失败认不到硬盘_CentOS7 用U盘安装卡住无法进入安装界面解决方案

使用U盘安装Centos系统找不到U盘解决方案补充&#xff1a;1、制作U盘启动盘请参考&#xff1a;使用UltraISO(软碟通)制作ubuntu U盘启动盘如果你安装centos7出现了下图这种情况不用担心&#xff0c;是因为安装centos7时找不到U盘稍等一下&#xff0c;如下图等到出现命令行时。输…

Django横向二级导航栏(鼠标悬空事件)

1 <!DOCTYPE html>2 <html lang"en" xmlns"http://www.w3.org/1999/html">3 <head>4 <meta charset"UTF-8">5 <title>{% block title %} base模板 {% endblock title%}</title>6 <style >…

浙江大学计算机学院1702班,测控1702:传道授业解惑 此间师者真情

2017年9月11日晚8:00&#xff0c;电气与信息工程学院测控技术与仪器1702班在德智学生公寓的天台上开展了一场别开生面的班主任见面交流会。测控1702班班主任文一章博士、电气院2017级本科辅导员金晶老师以及测控1702班的同学们参加了此次见面会。测控1702班班主任文一章1991年出…

通过小程序给公众号传递消息_多输入现场消息传递应用程序概念

通过小程序给公众号传递消息by Dawid Woldu戴维德沃尔杜(Dawid Woldu) 多输入现场消息传递应用程序概念 (A multi-input field messaging app concept) Some time ago I shared in a Medium article the idea for context aware messenger app. The idea challenged the desig…

Oracle【IT实验室】数据库备份与恢复之二:SQL*Loader

2.1 基本知识 Oracle 的 SQL* LOADER 可以将外部格式化的文本数据加载到数据库表中。通常 与 SPOOL导出文本数据方法配合使用。 1.命令格式 SQLLDR keywordvalue [&#xff0c;keywordvalue&#xff0c;……] 例&#xff1a;$ sqlldr user/pwd controlemp.ctl dataemp.dat ba…

关于spring 获取不到网站上的xsd的处理记录

2019独角兽企业重金招聘Python工程师标准>>> 前两天做一个项目还好好的&#xff0c;今天突然报出这个错误 cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element mvc:annotation-driven 应该是xml文件找不到相应…

蓝宝石英语怎么读_黑金和蓝宝石

这是一直以后我个人的一个理解误区&#xff0c;或者说是信息误区&#xff0c;就是这两个产品线&#xff0c;差别到底在哪里&#xff1f;以前我一直认为黑金的成分是纯天然的&#xff0c;而蓝宝石有一定的合成物质。这个信息一定是我从哪里读到的&#xff0c;由于无处求证&#…

秘密潜入2小辣椒_短暂潜入2次,我显然不知道自己作为开发人员正在做什么

秘密潜入2小辣椒by Zachary Kuhn扎卡里库恩(Zachary Kuhn) 那两次我显然不知道我作为开发人员正在做什么 (Those two times where I clearly had no clue what I was doing as a developer) Last week I had a short conversation with coworkers about how we had messed up …

提高你的javascript代码逼格系列之函数与数组

不知道大家有没有一种感觉&#xff0c;那就是自己写的javascript代码虽然能完全解决工作上的需要&#xff0c;但是&#xff0c;一眼望去&#xff0c;too simple&#xff01;&#xff01;&#xff01;简直就是一个傻子都能看懂的水平&#xff0c;于是&#xff0c;在工作之余&…

印度评论九章量子计算机,张礼立:中国 “九章”量子计算机到底厉害在哪?...

【背景信息】12月4日&#xff0c;《科学》杂志公布了中国“九章”的重大突破。 这台由中国科学技术大学潘建伟、陆朝阳等学者研制的76个光子的量子计算原型机&#xff0c;推动全球量子计算的前沿研究达到一个新高度。尽管距离实际应用仍有漫漫长路&#xff0c;但成功实现了“量…

手机web网页制作的认识(有关meta标签)

近日以来一直在看JQuery Mobile 一个手机开发框架&#xff0c;说实话真的很头疼的~~~~ 因为里面有很多的属性、方法和事件~~~ 下面是手机网页的一些认识&#xff1a; 一、<meta name"viewport" id"viewport" content"widthdevice-width, initial-s…

包打包和解析过程 unity_Unity学习—资源管理概览

本文介绍了 Unity 常用四种默认路径&#xff0c;以及 AssetDataBase、Resources、AssetBundle 和目前最新的 Addressable 四种资源管理方式文中所有 API 均以版本 2019.3 为准本文原地址&#xff1a;Unity学习—资源管理概览资源路径Application.dataPath官方文档只读&#xff…

graphql tools_声明式GraphQL:编写更少的代码,并使用graphql-tools完成更多工作

graphql toolsI’ve been working with GraphQL for a few months now, but only recently began using Apollo’s graphql-tools library. After learning a few idioms, I am able to mock up a functional API quickly. This is largely due to its low-code, declarative a…