Tôi đã cấu trúc lại mã của mình cho các lời hứa và xây dựng một chuỗi lời hứa dài phẳng tuyệt vời , bao gồm nhiều lệnh .then()
gọi lại. Cuối cùng, tôi muốn trả về một số giá trị tổng hợp và cần truy cập nhiều kết quả hứa hẹn trung gian . Tuy nhiên, các giá trị độ phân giải từ giữa chuỗi không nằm trong phạm vi trong lần gọi lại cuối cùng, làm cách nào để truy cập chúng?
function getExample() {
return promiseA(…).then(function(resultA) {
// Some processing
return promiseB(…);
}).then(function(resultB) {
// More processing
return // How do I gain access to resultA here?
});
}
Khi bạn cần truy cập các giá trị trung gian trong chuỗi của mình, bạn nên chia chuỗi của mình thành từng phần đơn lẻ mà bạn cần. Thay vì đính kèm một lệnh gọi lại và bằng cách nào đó cố gắng sử dụng tham số của nó nhiều lần, hãy đính kèm nhiều lệnh gọi lại vào cùng một lời hứa - bất cứ nơi nào bạn cần giá trị kết quả. Đừng quên, một lời hứa chỉ đại diện cho (proxy) một giá trị trong tương lai ! Tiếp theo để lấy một lời hứa từ lời hứa kia trong một chuỗi tuyến tính, hãy sử dụng các tổ hợp lời hứa mà thư viện của bạn cung cấp cho bạn để xây dựng giá trị kết quả.
Điều này sẽ dẫn đến một luồng điều khiển rất đơn giản, thành phần rõ ràng của các chức năng và do đó dễ dàng điều chỉnh.
function getExample() {
var a = promiseA(…);
var b = a.then(function(resultA) {
// some processing
return promiseB(…);
});
return Promise.all([a, b]).then(function([resultA, resultB]) {
// more processing
return // something using both resultA and resultB
});
}
Thay vì cấu trúc tham số trong lệnh gọi lại sau Promise.all
đó chỉ có sẵn với ES6, trong ES5, then
lệnh gọi sẽ được thay thế bằng một phương thức trợ giúp tiện lợi được cung cấp bởi nhiều thư viện hứa hẹn ( Q , Bluebird , when ,…) : .spread(function(resultA, resultB) { …
.
Bluebird cũng có một join
chức năng chuyên dụng để thay thế tổ hợp Promise.all
+ đó spread
bằng một cấu trúc đơn giản hơn (và hiệu quả hơn):
…
return Promise.join(a, b, function(resultA, resultB) { … });
Tất nhiên, vấn đề này cũng được các nhà thiết kế ngôn ngữ nhận ra. Họ đã làm rất nhiều việc và cuối cùng đề xuất chức năng không đồng bộ đã biến nó thành
Bạn không cần một lệnh then
gọi hoặc hàm gọi lại nào nữa, vì trong một hàm không đồng bộ (trả về một lời hứa khi được gọi), bạn có thể chỉ cần đợi các lời hứa giải quyết trực tiếp. Nó cũng có các cấu trúc điều khiển tùy ý như điều kiện, vòng lặp và mệnh đề try-catch, nhưng để thuận tiện, chúng tôi không cần chúng ở đây:
async function getExample() {
var resultA = await promiseA(…);
// some processing
var resultB = await promiseB(…);
// more processing
return // something using both resultA and resultB
}
Trong khi chờ đợi ES8, chúng tôi đã sử dụng một kiểu cú pháp rất giống nhau. ES6 đi kèm với các chức năng của trình tạo , cho phép chia nhỏ việc thực thi thành nhiều phần tại các yield
từ khóa được đặt tùy ý . Các lát cắt đó có thể được chạy sau nhau, độc lập, thậm chí không đồng bộ - và đó chỉ là những gì chúng ta làm khi muốn đợi giải quyết lời hứa trước khi chạy bước tiếp theo.
Có các thư viện chuyên dụng (như co hoặc task.js ), nhưng cũng có nhiều thư viện hứa hẹn có các hàm trợ giúp ( Q , Bluebird , when ,…) thực hiện việc thực thi từng bước bất đồng bộ này cho bạn khi bạn cung cấp cho chúng một hàm trình tạo mang lại những lời hứa.
var getExample = Promise.coroutine(function* () {
// ^^^^^^^^^^^^^^^^^ Bluebird syntax
var resultA = yield promiseA(…);
// some processing
var resultB = yield promiseB(…);
// more processing
return // something using both resultA and resultB
});
Điều này đã hoạt động trong Node.js kể từ phiên bản 4.0, cũng có một số trình duyệt (hoặc phiên bản dành cho nhà phát triển của chúng) đã hỗ trợ cú pháp trình tạo tương đối sớm.
Tuy nhiên, nếu bạn muốn / cần tương thích ngược, bạn không thể sử dụng chúng mà không có bộ chuyển tiếp. Cả hai hàm bộ tạo và hàm không đồng bộ đều được hỗ trợ bởi công cụ hiện tại, hãy xem ví dụ tài liệu của Babel về bộ tạo và hàm không đồng bộ .
Và sau đó, cũng có nhiều ngôn ngữ biên dịch sang JS khác
được dành riêng để giảm bớt lập trình không đồng bộ. Chúng thường sử dụng cú pháp tương tự như await
, (ví dụ: Iced CoffeeScript ), nhưng cũng có những cú pháp khác có chú thích-giống do
Haskell (ví dụ như LatteJs , monadic , PureScript hoặc LispyScript ).
Gán các giá trị cần-dùng-cho-sau này cho các biến và sau đó nhận giá trị của chúng thông qua kiểm tra đồng bộ. Ví dụ sử dụng .value()
phương pháp của bluebird nhưng nhiều thư viện cung cấp phương pháp tương tự.
function getExample() {
var a = promiseA(…);
return a.then(function() {
// some processing
return promiseB(…);
}).then(function(resultB) {
// a is guaranteed to be fulfilled here so we can just retrieve its
// value synchronously
var aValue = a.value();
});
}
Điều này có thể được sử dụng cho bao nhiêu giá trị tùy thích:
function getExample() {
var a = promiseA(…);
var b = a.then(function() {
return promiseB(…)
});
var c = b.then(function() {
return promiseC(…);
});
var d = c.then(function() {
return promiseD(…);
});
return d.then(function() {
return a.value() + b.value() + c.value() + d.value();
});
}
Sử dụng các bao đóng để duy trì phạm vi của các biến (trong trường hợp của chúng tôi là tham số hàm gọi lại thành công) là giải pháp JavaScript tự nhiên. Với các lời hứa, chúng ta có thể lồng và làm phẳng các lệnh .then()
gọi lại một cách tùy ý - chúng tương đương nhau về mặt ngữ nghĩa, ngoại trừ phạm vi của lệnh bên trong.
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return promiseB(…).then(function(resultB) {
// more processing
return // something using both resultA and resultB;
});
});
}
Tất nhiên, đây là việc xây dựng một kim tự tháp thụt vào. Nếu thụt lề ngày càng lớn, bạn vẫn có thể áp dụng các công cụ cũ để chống lại kim tự tháp của sự diệt vong : modularize, sử dụng các hàm bổ sung được đặt tên và làm phẳng chuỗi hứa hẹn ngay khi bạn không cần biến nữa.
Về lý thuyết, bạn luôn có thể tránh nhiều hơn hai cấp độ lồng nhau (bằng cách đặt tất cả các bao đóng là rõ ràng), trong thực tế, hãy sử dụng càng nhiều càng tốt.
function getExample() {
// preprocessing
return promiseA(…).then(makeAhandler(…));
}
function makeAhandler(…)
return function(resultA) {
// some processing
return promiseB(…).then(makeBhandler(resultA, …));
};
}
function makeBhandler(resultA, …) {
return function(resultB) {
// more processing
return // anything that uses the variables in scope
};
}
Bạn cũng có thể sử dụng các hàm trợ giúp cho loại ứng dụng từng phần này , chẳng hạn như _.partial
từ Underscore / lodash hoặc phương thức gốc.bind()
, để giảm thụt lề hơn nữa:
function getExample() {
// preprocessing
return promiseA(…).then(handlerA);
}
function handlerA(resultA) {
// some processing
return promiseB(…).then(handlerB.bind(null, resultA));
}
function handlerB(resultA, resultB) {
// more processing
return // anything that uses resultA and resultB
}
Tương tự như lồng các lệnh gọi lại, kỹ thuật này dựa vào các bao đóng. Tuy nhiên, chuỗi vẫn ổn định - thay vì chỉ truyền kết quả mới nhất, một số đối tượng trạng thái được chuyển cho mỗi bước. Các đối tượng trạng thái này tích lũy kết quả của các hành động trước đó, phân phối lại tất cả các giá trị sẽ cần sau đó cộng với kết quả của tác vụ hiện tại.
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return promiseB(…).then(b => [resultA, b]); // function(b) { return [resultA, b] }
}).then(function([resultA, resultB]) {
// more processing
return // something using both resultA and resultB
});
}
Ở đây, mũi tên nhỏ đó b => [resultA, b]
là hàm đóng lại resultA
và chuyển một mảng của cả hai kết quả cho bước tiếp theo. Trong đó sử dụng cú pháp hủy cấu trúc tham số để chia nhỏ lại trong các biến đơn.
Trước khi cấu trúc hủy có sẵn với ES6, một phương pháp trợ giúp tiện lợi được gọi là .spread()
đã được cung cấp bởi nhiều thư viện hứa hẹn ( Q , Bluebird , when ,…). Nó cần một hàm có nhiều tham số - một cho mỗi phần tử mảng - được sử dụng như .spread(function(resultA, resultB) { …
.
Tất nhiên, việc đóng đó cần thiết ở đây có thể được đơn giản hóa hơn nữa bằng một số hàm trợ giúp, ví dụ:
function addTo(x) {
// imagine complex `arguments` fiddling or anything that helps usability
// but you get the idea with this simple one:
return res => [x, res];
}
…
return promiseB(…).then(addTo(resultA));
Ngoài ra, bạn có thể sử dụng Promise.all
để tạo ra lời hứa cho mảng:
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return Promise.all([resultA, promiseB(…)]); // resultA will implicitly be wrapped
// as if passed to Promise.resolve()
}).then(function([resultA, resultB]) {
// more processing
return // something using both resultA and resultB
});
}
Và bạn có thể không chỉ sử dụng mảng mà còn sử dụng các đối tượng phức tạp tùy ý. Ví dụ: với _.extend
hoặc Object.assign
trong một chức năng trợ giúp khác:
function augment(obj, name) {
return function (res) { var r = Object.assign({}, obj); r[name] = res; return r; };
}
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return promiseB(…).then(augment({resultA}, "resultB"));
}).then(function(obj) {
// more processing
return // something using both obj.resultA and obj.resultB
});
}
Mặc dù mô hình này đảm bảo một chuỗi phẳng và các đối tượng trạng thái rõ ràng có thể cải thiện độ rõ ràng, nhưng nó sẽ trở nên tẻ nhạt đối với một chuỗi dài. Đặc biệt là khi bạn chỉ cần trạng thái lẻ tẻ, bạn vẫn phải vượt qua nó qua từng bước. Với giao diện cố định này, các lệnh gọi lại đơn lẻ trong chuỗi được kết hợp khá chặt chẽ và không linh hoạt để thay đổi. Nó làm cho việc bao gồm các bước đơn lẻ khó hơn và các lệnh gọi lại không thể được cung cấp trực tiếp từ các mô-đun khác - chúng luôn cần được bọc trong mã soạn sẵn quan tâm đến trạng thái. Các chức năng trợ giúp trừu tượng như trên có thể làm dịu cơn đau một chút, nhưng nó sẽ luôn hiện diện.
Giải pháp nhỏ (nhưng không phù hợp và đúng hơn là sai sót) là chỉ sử dụng các biến phạm vi cao hơn (mà tất cả các lệnh gọi lại trong chuỗi đều có quyền truy cập) và ghi giá trị kết quả vào chúng khi bạn nhận được chúng:
function getExample() {
var resultA;
return promiseA(…).then(function(_resultA) {
resultA = _resultA;
// some processing
return promiseB(…);
}).then(function(resultB) {
// more processing
return // something using both resultA and resultB
});
}
Thay vì nhiều biến, người ta cũng có thể sử dụng một đối tượng (ban đầu trống), trên đó kết quả được lưu trữ dưới dạng các thuộc tính được tạo động.
Giải pháp này có một số nhược điểm:
Thư viện Bluebird khuyến khích sử dụng một đối tượng được truyền cùng, sử dụng phương thức của họbind()
để gán một đối tượng ngữ cảnh cho một chuỗi hứa hẹn. Nó sẽ có thể truy cập được từ mỗi chức năng gọi lại thông qua this
từ khóa không sử dụng được . Mặc dù các thuộc tính đối tượng dễ mắc lỗi chính tả không được phát hiện hơn là các biến, nhưng mẫu này khá thông minh:
function getExample() {
return promiseA(…)
.bind({}) // Bluebird only!
.then(function(resultA) {
this.resultA = resultA;
// some processing
return promiseB(…);
}).then(function(resultB) {
// more processing
return // something using both this.resultA and resultB
}).bind(); // don't forget to unbind the object if you don't want the
// caller to access it
}
Cách tiếp cận này có thể được mô phỏng dễ dàng trong các thư viện hứa hẹn không hỗ trợ .bind (mặc dù theo cách hơi dài dòng hơn và không thể được sử dụng trong một biểu thức):
function getExample() {
var ctx = {};
return promiseA(…)
.then(function(resultA) {
this.resultA = resultA;
// some processing
return promiseB(…);
}.bind(ctx)).then(function(resultB) {
// more processing
return // something using both this.resultA and resultB
}.bind(ctx));
}
Sử dụng một đối tượng có phạm vi cục bộ để thu thập các kết quả trung gian trong chuỗi hứa hẹn là một cách tiếp cận hợp lý cho câu hỏi bạn đặt ra. Hãy xem xét đoạn mã sau:
function getExample(){
//locally scoped
const results = {};
return promiseA(paramsA).then(function(resultA){
results.a = resultA;
return promiseB(paramsB);
}).then(function(resultB){
results.b = resultB;
return promiseC(paramsC);
}).then(function(resultC){
//Resolve with composite of all promises
return Promise.resolve(results.a + results.b + resultC);
}).catch(function(error){
return Promise.reject(error);
});
}
Node 7.4 hiện hỗ trợ các cuộc gọi async / await với cờ hòa hợp.
Thử đi:
async function getExample(){
let response = await returnPromise();
let response2 = await returnPromise2();
console.log(response, response2)
}
getExample()
và chạy tệp với:
node --harmony-async-await getExample.js
Đơn giản như có thể được!
Dạo này mình cũng gặp một số câu hỏi như bạn. Cuối cùng, tôi tìm thấy một giải pháp tốt với câu hỏi, nó đơn giản và tốt để đọc. Tôi hy vọng điều này có thể giúp bạn.
Theo how-to-chain-javascript-promise
được rồi, hãy xem mã:
const firstPromise = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('first promise is completed');
resolve({data: '123'});
}, 2000);
});
};
const secondPromise = (someStuff) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('second promise is completed');
resolve({newData: `${someStuff.data} some more data`});
}, 2000);
});
};
const thirdPromise = (someStuff) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('third promise is completed');
resolve({result: someStuff});
}, 2000);
});
};
firstPromise()
.then(secondPromise)
.then(thirdPromise)
.then(data => {
console.log(data);
});
Một câu trả lời khác, sử dụng babel-node
phiên bản <6
Sử dụng async - await
npm install -g [email protected]
example.js:
async function getExample(){
let response = await returnPromise();
let response2 = await returnPromise2();
console.log(response, response2)
}
getExample()
Sau đó, chạy babel-node example.js
và thì đấy!
Tôi sẽ không sử dụng mẫu này trong mã của riêng mình vì tôi không phải là người thích sử dụng các biến toàn cục. Tuy nhiên, nó sẽ hoạt động.
Người dùng là một mô hình Mongoose được quảng bá.
var globalVar = '';
User.findAsync({}).then(function(users){
globalVar = users;
}).then(function(){
console.log(globalVar);
});
Một câu trả lời khác, sử dụng trình thực thi tuần tự nsynjs :
function getExample(){
var response1 = returnPromise1().data;
// promise1 is resolved at this point, '.data' has the result from resolve(result)
var response2 = returnPromise2().data;
// promise2 is resolved at this point, '.data' has the result from resolve(result)
console.log(response, response2);
}
nynjs.run(getExample,{},function(){
console.log('all done');
})
function synchronousCode() {
var urls=[
"https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js",
"https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js",
"https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"
];
for(var i=0; i<urls.length; i++) {
var len=window.fetch(urls[i]).data.text().data.length;
// ^ ^
// | +- 2-nd promise result
// | assigned to 'data'
// |
// +-- 1-st promise result assigned to 'data'
//
console.log('URL #'+i+' : '+urls[i]+", length: "+len);
}
}
nsynjs.run(synchronousCode,{},function(){
console.log('all done');
})
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>
Khi sử dụng bluebird, bạn có thể sử dụng .bind
phương thức để chia sẻ các biến trong chuỗi hứa hẹn:
somethingAsync().bind({})
.spread(function (aValue, bValue) {
this.aValue = aValue;
this.bValue = bValue;
return somethingElseAsync(aValue, bValue);
})
.then(function (cValue) {
return this.aValue + this.bValue + cValue;
});
vui lòng kiểm tra liên kết này để biết thêm thông tin:
function getExample() {
var retA, retB;
return promiseA(…).then(function(resultA) {
retA = resultA;
// Some processing
return promiseB(…);
}).then(function(resultB) {
// More processing
//retA is value of promiseA
return // How do I gain access to resultA here?
});
}
một cách dễ dàng: D
Tôi nghĩ bạn có thể sử dụng hàm băm của RSVP.
Một cái gì đó như dưới đây:
const mainPromise = () => {
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('first promise is completed');
resolve({data: '123'});
}, 2000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('second promise is completed');
resolve({data: '456'});
}, 2000);
});
return new RSVP.hash({
prom1: promise1,
prom2: promise2
});
};
mainPromise()
.then(data => {
console.log(data.prom1);
console.log(data.prom2);
});
Giải pháp:
Bạn có thể đặt các giá trị trung gian trong phạm vi trong bất kỳ hàm 'then' nào sau này một cách rõ ràng, bằng cách sử dụng 'bind'. Đó là một giải pháp tốt mà không yêu cầu thay đổi cách Promises hoạt động và chỉ yêu cầu một hoặc hai dòng mã để truyền các giá trị giống như lỗi đã được truyền.
Đây là một ví dụ đầy đủ:
// Get info asynchronously from a server
function pGetServerInfo()
{
// then value: "server info"
} // pGetServerInfo
// Write into a file asynchronously
function pWriteFile(path,string)
{
// no then value
} // pWriteFile
// The heart of the solution: Write formatted info into a log file asynchronously,
// using the pGetServerInfo and pWriteFile operations
function pLogInfo(localInfo)
{
var scope={localInfo:localInfo}; // Create an explicit scope object
var thenFunc=p2.bind(scope); // Create a temporary function with this scope
return (pGetServerInfo().then(thenFunc)); // Do the next 'then' in the chain
} // pLogInfo
// Scope of this 'then' function is {localInfo:localInfo}
function p2(serverInfo)
{
// Do the final 'then' in the chain: Writes "local info, server info"
return pWriteFile('log',this.localInfo+','+serverInfo);
} // p2
Giải pháp này có thể được gọi như sau:
pLogInfo("local info").then().catch(err);
(Lưu ý: một phiên bản phức tạp và đầy đủ hơn của giải pháp này đã được thử nghiệm, nhưng không phải phiên bản ví dụ này, vì vậy nó có thể có lỗi.)
Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.
Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?
Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.
Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.
Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?
Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.
BoJack Horseman (Ảnh: Netflix) BoJack Horseman bắt đầu mùa thứ ba với sự xuất hiện của nhân vật tiêu biểu, người vẫn đang theo đuổi những lời khen ngợi từ giới phê bình trong một nỗ lực tuyệt vọng để tìm ra ý nghĩa trong cuộc sống của mình. Mùa thứ hai về số phận bi kịch của Raphael Bob-Waksberg dày đặc những trò đùa cũng như tuyệt vọng.
Bản nâng cấp Phiên bản 8.0 gần đây của Tesla đối với hệ thống Lái xe tự động được thiết kế để cải thiện hệ thống và mối quan hệ của nó với người lái.
Chắc chắn khi con cái chúng ta xem lại các chương trình chúng ta đã xem vào khoảng năm 2015, chúng sẽ thấy UnREAL, một chương trình truyền hình mới chiếu vào tối Thứ Hai của Lifetime — bạn sẽ thấy đúng lúc, sẽ phát sóng ngay sau khi The Bachelor kết thúc — như một chương trình không thể được thực hiện vào bất kỳ thời điểm nào khác trong lịch sử truyền hình, nhưng một chương trình cảm thấy cần thiết để xem bây giờ. UnREAL có sự tham gia của Shiri Appleby trong vai Rachel, một nhà sản xuất truyền hình cho một chương trình về cơ bản là The Bachelor, mặc dù trong thế giới này, nó được gọi là Vĩnh viễn.
Thông báo chính thức đến trực tiếp từ trang web của Star Wars: Fantastic Four, đạo diễn Josh Trank, một người bí ẩn không xuất hiện tại đại hội Star Wars Celebration gần đây, sẽ không chỉ đạo phần hai Star Wars Anthology. Đây là tuyên bố được đăng ngày hôm qua: Tất cả thực sự là ngôn ngữ rất lịch sự, nhưng một bài báo của Hollywood Reporter cho thấy tất cả đều không tốt ở hậu trường, gọi sự ra đi là "một vụ sa thải" một phần dựa trên "hành vi bất thường" của Trank trong khi quay Fantastic Four: The Bài báo trích dẫn các nguồn gọi là Trank “đôi khi thiếu quyết đoán và thiếu sáng tạo,” và lưu ý rằng Fantastic Four, khởi chiếu vào ngày 7 tháng 8, đã được khởi động lại vào cuối tháng 4.
McCain, người đang làm việc cho một album mới, lần đầu tiên bước vào vòng kết nối vào tối thứ Sáu ở Nashville
Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!
Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!
Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không
Đối với tôi, mọi thứ là về dòng đầu tiên đó và nó sẽ đưa bạn đến đâu. Một số nhà văn bị điều khiển bởi cốt truyện, sự sắp xếp tinh tế của các quân cờ, trong khi những người khác bị lôi cuốn bởi một nhân vật và khả năng thực hiện một cuộc hành trình với một người bạn hư cấu mới.
Cuối hè đầu thu là mùa hoài niệm. Những chiếc đèn đường chiếu ánh sáng của chúng qua những con đường đẫm mưa, và những chiếc lá dưới chân - màu đỏ cam tắt trong bóng chạng vạng - là lời nhắc nhở về những ngày đã qua.
Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.
Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.