javascript 异步_JavaScript异步操作使用回调或Promise读取文件目录

javascript 异步

异步操作-我们为什么要关心?(Asynchronous Operation — Why do we care?)

JavaScript is a synchronous, blocking, single threaded language. Synchronous single threaded means JavaScript waits for the task to be completed before being able to move on to the next task. However, Asynchronous JavaScript makes it so much faster if each task takes a really long time! Instead of waiting for the task beforehand to move on, there can be independent threads to start the tasks simultaneously.

JavaScript是一种同步的,阻塞的单线程语言。 同步单线程意味着JavaScript等待任务完成,然后才能继续执行下一个任务。 但是,如果每个任务花费的时间很长,异步JavaScript会使其更快! 无需等待任务继续进行,可以有独立的线程来同时启动任务。

Image for post
http://www.phpmind.com/blog/2017/05/synchronous-and-asynchronous/ http://www.phpmind.com/blog/2017/05/synchronous-and-asynchronous/

In the computer programming world, synchronous and asynchronous may still be considered “fast” in human time. But let’s imagine a scenario if a request was sent to read an entire database of files and there are files in there are REALLY huge therefore take a long time to read. Instead of waiting, what if we can start reading the other files in the directory at the same time. This is Asynchronous JavaScript.

在计算机编程世界中,同步和异步在人类时代仍然可以被视为“快速”。 但是,让我们想象一个场景,如果发送了一个请求以读取整个文件数据库,并且其中的文件确实很大,那么读取时间就很长。 无需等待,而可以开始同时读取目录中的其他文件了。 这是异步JavaScript。

异步操作-代码样式 (Asynchronous Operation — Code Styles)

In JavaScript, functions are first class citizens. This means functions can be treated like values of other types. Functions can be passed to other functions as arguments, returned from other functions as values, and stored in variables.

在JavaScript中,函数是一等公民。 这意味着函数可以像其他类型的值一样对待。 函数可以作为参数传递给其他函数,可以作为值从其他函数返回,并存储在变量中。

Async operations are put into an event queue which runs after the main thread has finished processing so that they do not stop subsequent JavaScript from running.

异步操作被放入事件队列中,该事件队列在主线程完成处理之后运行,以便它们不会阻止后续JavaScript运行。

There are 2 main asynchronous concepts that JavaScript uses which leverage functions first class citizenship:

JavaScript使用了两个主要的异步概念,它们利用了一流的公民身份功能:

  1. Async Callbacks

    异步回调
  2. Promises

    承诺

For other examples, to help you further solidify your understanding of these 2 concepts.

对于其他示例,可以帮助您进一步巩固对这两个概念的理解。

Let’s consider an AJAX (Asynchronous JavaScript and XML) request to the server.

让我们考虑对服务器的AJAX(异步JavaScript和XML)请求。

Image for post
http://www.phpmind.com/blog/2017/05/synchronous-and-asynchronous/ http://www.phpmind.com/blog/2017/05/synchronous-and-asynchronous/

The user clicks on the browser which results in sending an HTTP request to the server to read an entire directory, which could take some time. Instead of having the browser stop running any other functions and wait for the response, another function is set up to wait for this response and react when the response is received.

用户单击浏览器,这将向服务器发送HTTP请求以读取整个目录,这可能需要一些时间。 代替让浏览器停止运行任何其他功能并等待响应,而是设置了另一个功能来等待该响应并在收到响应时做出React。

Let’s see how we can write these Asynchronous Operations.

让我们看看如何编写这些异步操作。

异步回调 (Async Callbacks)

Not all callbacks are asynchronous. A callback using .map() in this context isn’t being delayed.

并非所有的回调都是异步的。 在此上下文中使用.map()回调不会延迟。

[1,2,3].map((i) => i + 5)

On the other hand, waiting for the user to click to invoke a function. Waiting for a callback to execute during a particular time. This callback (the second parameter) is an async callback. Once the event listener (‘click’) is heard, the callback will execute.

另一方面,等待用户单击以调用功能。 等待在特定时间内执行回调。 该回调(第二个参数)是一个异步回调。 听到事件监听器(“点击”)后,便会执行回调。

$('#btn').on('click', () =>
console.log('Callbacks are everywhere')
)

A GET request has been sent to read the whole directory. Let’s read all files. For now we will just read the file name (not the file content because of the extra complexity) and return that data. The callbacks are using a pattern called continuation passing style. Notice also we are following the error first callback pattern that adopted by the nodejs community.

已发送GET请求以读取整个目录。 让我们阅读所有文件。 现在,我们仅读取文件名(由于额外的复杂性而不是文件内容)并返回该数据。 回调使用称为延续传递样式的模式。 还要注意,我们遵循的是nodejs社区采用的错误优先回调模式。

const fs = require('fs');
const path = require('path');exports.readAll = (callback) => {
var data = [];
fs.readdir(`${exports.dataDir}`, (err, files) => {
if (err) {
throw 'error reading dir';
} else {
files.forEach((file) => {
id = file.slice(0, 5);
data.push({ id: id, text: id });
});
callback(null, data);
}
});
};exports.readOne = (id, callback) => {
fs.readFile(`${exports.dataDir}/${id}.txt`, 'utf8',
(err, text) => {
if (err) {
callback(new Error(`No item with id: ${id}`));
} else {
callback(null, { id, text });
}
});
};

Unfortunately, if we add more layers of callbacks, which results in nested callbacks within nested callbacks, we enter the world of “Callback Hell”.

不幸的是,如果我们添加更多的回调层,从而在嵌套回调中产生嵌套回调,我们将进入“回调地狱”的世界。

Image for post
https://medium.com/@js_tut/the-great-escape-from-callback-hell-3006fa2c82e https://medium.com/@js_tut/the-great-escape-from-callback-hell-3006fa2c82e

A common approach to help us with “Callback hell” is to modularize our code well. This helps with the readability of “callback hell” however it may still be extremely hard to sequentially track what is happening.

帮助我们进行“回调地狱”的常见方法是很好地模块化我们的代码。 这有助于“回调地狱”的可读性,但是依序跟踪正在发生的事情仍然非常困难。

承诺 (Promises)

Promises are the newer style of asynchronous code and specifically made for handling async operations. A promises will execute your request if the response is true. If not, a promise won’t. Promises have 3 states:

Promise是更新的异步代码样式,专门用于处理异步操作。 如果响应为true,则promises将执行您的请求。 如果没有,诺言就不会。 承诺有3种状态:

  • Pending — the initial state of the Promise before operation (request) begins

    待定-操作(请求)开始之前Promise的初始状态

  • Fulfilled — the operation (request) was completed

    已完成-操作(请求)已完成

  • Rejected — the operation (request) did not complete, there was an error

    已拒绝-操作(请求)未完成,出现错误

Constructing a Promise uses the new keyword, creating a new instance of a Promise . The Promise constructor takes a single argument a (callback) function that has resolve and reject as it’s arguments.

构造Promise使用new关键字,创建Promisenew实例。 Promise构造函数将一个参数(回调)作为一个参数,该函数具有resolvereject作为参数。

const promise = new Promise(function(resolve, reject) {
// promise description
})

resolve allows us to update the state of the promise to fulfilled.

resolve使我们能够更新兑现承诺的状态。

reject allow us to update the state of the promise to rejected.

reject允许我们更新承诺被拒绝的状态。

A promise is a plain JavaScript object and has the .then and .catch method which can be invoked. If the promise is fulfilled, the function passed into .then will be invoked. Otherwise if the promise is rejected (the async request fails), the function passed into .catch will be invoked.

甲诺是一个普通JavaScript对象和具有.then.catch可以调用方法。 如果实现了诺言.then则将调用传递给.then的函数。 否则,如果.catch被拒绝(异步请求失败),则将调用传递给.catch的函数。

连锁承诺 (Chaining Promises)

The .then and .catch will return a new promise which allows us to chain promises. This is an improvement to our “callback hell” scenario. We can think more sequentially.

.then.catch会返回一个新的承诺,使我们能够链的承诺。 这是对我们的“回调地狱”方案的改进。 我们可以顺序地思考。

function getPromise () {
return new Promise((resolve) => {
setTimeout(resolve, 2000)
})
}

function logA () {
console.log('A')
}

function logB () {
console.log('B')
}

function logCAndThrow () {
console.log('C')

throw new Error()
}

function catchError () {
console.log('Error!')
}

getPromise()
.then(logA) // A
.then(logB) // B
.then(logCAndThrow) // C
.catch(catchError) // Error!

承诺与承诺 (Promisification and Promise.all)

Promisification is a simple transformation. Essentially it is the conversion of a function that is has an error first callback style and returns that as a promise. Function and libraries that are callback-based with the correct formatting can be ‘promisified’. See example of the asynchronous readFile in node’s fs-module.

承诺化是一个简单的转变。 本质上是具有错误优先回调样式的函数的转换,并将其作为promise返回。 可以“承诺”使用正确格式的基于回调的函数和库。 请参阅节点的fs -module中的异步readFile示例。

var readFile = Promise.promisify(require("fs").readFile);

readFile("myfile.js", "utf8").then(function(contents) {
return eval(contents);
}).then(function(result) {
console.log("The result of evaluating myfile.js", result);
}).catch(function(e) {
console.log("Error reading file", e);
});

Transform the entire object with .promisifyAll will promisifisy the entire object going through the object’s properties and create an async equivalent of each function on the object and its prototype chain. The original methods are not overwritten but new promisified methods will have and Async-suffix.

使用.promisifyAll转换整个对象将使整个对象遍历对象的属性,并创建对象及其原型链上每个函数的异步等效项。 原来的方法就不会被覆盖,但新promisified方法将和Async -suffix。

var fs = Promise.promisifyAll(require("fs"));

fs.readFileAsync("myfile.js", "utf8").then(function(contents) {
console.log(contents);
}).catch(function(e) {
console.log("Error reading file", e);
});

With Promise.all() we can aggregate a group of promises in an array (an iterable) as an input and return a single Promise that resolves to an array of results.

使用Promise.all()我们可以将一组promise集合在一个数组(可迭代)中作为输入,并返回一个解析为结果数组的Promise

  • Resolves when every input Promise has resolved

    在每个输入Promise解决后解决
  • Rejects when any of the input Promise has rejected

    当任何输入Promise被拒绝时拒绝

This method is useful for aggregating results of multiple promises and used when multiple asynchronous tasks are dependent on another to complete successfully.

此方法对于汇总多个Promise的结果很有用,并在多个异步任务依赖于另一个异步任务才能成功完成时使用。

With all that we now know about promises let’s read our directory with the Promise Async operation.

现在我们已经了解了关于Promise的所有信息,让我们使用Promise Async操作来读取目录。

const fs = require('fs');
const path = require('path');
const Promise = require('bluebird');
const fsAsync = Promise.promisifyAll(fs);exports.readOne = (id, callback) => {
return fsAsync
.readFileAsync(`${exports.dataDir}/${id}.txt`, 'utf8')
.then((text) => callback(null, { id, text }))
.catch((err) => callback(new Error(`No item with id: ${id}`)))
};exports.readAll = (callback) => {
var readFileAsync = Promise.promisify(exports.readOne);
var promises = [];
return fsAsync
.readdirAsync(`${exports.dataDir}`).then((files) => {
_.each(files, (file) => {
var id = file.slice(0, 5);
promises.push(readFileAsync(id));
});
Promise.all(promises)
.then((promise) => callback(null, promise))
.catch((err) => callback(
new Error('error reading directory'))
);
});
};

With promises, we can now read the contents of each file in the directory asynchronously using Promise.all() . As we are reading the firection, each file is now being read as a promise and pushed into the promise array. If the all the files are read successfully, the callback in the RESTful route (Read all route) in the server will run.

有了promise,我们现在可以使用Promise.all()异步读取目录中每个文件的内容。 当我们阅读规范时,每个文件现在都被作为一个诺言读取并推入诺言数组。 如果所有文件均已成功读取,则将运行服务器中RESTful路由(读取所有路由)中的回调。

Asynchronous operation is very powerful. It will be up to us to determine whether we want to run code synchronous or asynchronous depending on the task at hand. If an operation take time like navigating a database, it may be better to have another thread complete this task asynchronously.

异步操作非常强大。 由我们来决定是要根据手头的任务来同步还是异步运行代码。 如果像导航数据库这样的操作花费时间,则最好让另一个线程异步完成此任务。

翻译自: https://medium.com/dev-genius/javascript-asynchronous-operation-read-file-directory-with-callback-or-promises-9d74a236a928

javascript 异步

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值