Tại sao biến của tôi không thay đổi sau khi tôi sửa đổi nó bên trong một hàm? - Tham chiếu mã không đồng bộ

767
Fabrício Matté 2014-05-15 13:55.

Cho các ví dụ sau đây, tại sao outerScopeVarkhông xác định trong mọi trường hợp?

var outerScopeVar;

var img = document.createElement('img');
img.onload = function() {
    outerScopeVar = this.width;
};
img.src = 'lolcat.png';
alert(outerScopeVar);

var outerScopeVar;
setTimeout(function() {
    outerScopeVar = 'Hello Asynchronous World!';
}, 0);
alert(outerScopeVar);

// Example using some jQuery
var outerScopeVar;
$.post('loldog', function(response) {
    outerScopeVar = response;
});
alert(outerScopeVar);

// Node.js example
var outerScopeVar;
fs.readFile('./catdog.html', function(err, data) {
    outerScopeVar = data;
});
console.log(outerScopeVar);

// with promises
var outerScopeVar;
myPromise.then(function (response) {
    outerScopeVar = response;
});
console.log(outerScopeVar);

// geolocation API
var outerScopeVar;
navigator.geolocation.getCurrentPosition(function (pos) {
    outerScopeVar = pos;
});
console.log(outerScopeVar);

Tại sao nó xuất hiện undefinedtrong tất cả các ví dụ này? Tôi không muốn giải pháp thay thế, tôi muốn biết tại sao điều này lại xảy ra.


Lưu ý: Đây là một câu hỏi chuẩn cho tính không đồng bộ của JavaScript . Vui lòng cải thiện câu hỏi này và thêm nhiều ví dụ đơn giản hơn mà cộng đồng có thể xác định.

6 answers

605
Fabrício Matté 2014-05-15 13:55.

Câu trả lời một từ: không đồng bộ .

Lời nói đầu

Chủ đề này đã được lặp lại ít nhất vài nghìn lần, tại đây, trong Stack Overflow. Do đó, trước hết tôi muốn chỉ ra một số tài nguyên cực kỳ hữu ích:


Câu trả lời cho câu hỏi trong tầm tay

Hãy theo dõi các hành vi phổ biến trước. Trong tất cả các ví dụ, hàm outerScopeVarđược sửa đổi bên trong một hàm . Hàm đó rõ ràng không được thực thi ngay lập tức, nó đang được gán hoặc truyền như một đối số. Đó là những gì chúng tôi gọi là một cuộc gọi lại .

Bây giờ câu hỏi là, cuộc gọi lại đó được gọi khi nào?

Nó phụ thuộc vào từng trường hợp. Hãy thử theo dõi lại một số hành vi phổ biến:

  • img.onloadcó thể được gọi vào một lúc nào đó trong tương lai , khi (và nếu) hình ảnh đã tải thành công.
  • setTimeoutcó thể được gọi đôi khi trong tương lai , sau khi trì hoãn đã hết hạn và thời gian chờ đã không bị hủy bởi clearTimeout. Lưu ý: ngay cả khi sử dụng 0làm độ trễ, tất cả các trình duyệt đều có giới hạn độ trễ thời gian chờ tối thiểu (được chỉ định là 4ms trong thông số kỹ thuật HTML5).
  • Lệnh $.postgọi lại của jQuery có thể được gọi vào một lúc nào đó trong tương lai , khi (và nếu) yêu cầu Ajax đã được hoàn thành thành công.
  • Node.js's fs.readFilecó thể được gọi vào một thời điểm nào đó trong tương lai , khi tệp đã được đọc thành công hoặc gặp lỗi.

Trong mọi trường hợp, chúng tôi có một cuộc gọi lại có thể chạy đôi khi trong tương lai . "Đôi khi trong tương lai" này được chúng tôi gọi là luồng không đồng bộ .

Thực thi không đồng bộ bị đẩy ra khỏi luồng đồng bộ. Nghĩa là, mã không đồng bộ sẽ không bao giờ thực thi trong khi ngăn xếp mã đồng bộ đang thực thi. Đây là ý nghĩa của JavaScript là một luồng.

Cụ thể hơn, khi công cụ JS không hoạt động - không thực thi một chồng (a) mã đồng bộ - nó sẽ thăm dò các sự kiện có thể đã kích hoạt lệnh gọi lại không đồng bộ (ví dụ: hết thời gian chờ, đã nhận được phản hồi mạng) và thực thi chúng lần lượt. Đây được coi là Vòng lặp sự kiện .

Nghĩa là, mã không đồng bộ được đánh dấu trong các hình màu đỏ vẽ tay chỉ có thể thực thi sau khi tất cả các mã đồng bộ còn lại trong các khối mã tương ứng của chúng đã thực thi:

Nói tóm lại, các hàm gọi lại được tạo đồng bộ nhưng thực thi không đồng bộ. Bạn chỉ không thể dựa vào việc thực thi một hàm không đồng bộ cho đến khi bạn biết nó đã được thực thi, và làm thế nào để thực hiện điều đó?

Nó là đơn giản, thực sự. Logic phụ thuộc vào việc thực thi hàm không đồng bộ nên được khởi động / gọi từ bên trong hàm không đồng bộ này. Ví dụ, di chuyển cả alerts và console.logs bên trong hàm gọi lại sẽ xuất ra kết quả mong đợi, vì kết quả có sẵn tại thời điểm đó.

Triển khai logic gọi lại của riêng bạn

Thường thì bạn cần làm nhiều việc hơn với kết quả từ một hàm không đồng bộ hoặc làm những việc khác với kết quả tùy thuộc vào vị trí mà hàm không đồng bộ đã được gọi. Hãy giải quyết một ví dụ phức tạp hơn một chút:

var outerScopeVar;
helloCatAsync();
alert(outerScopeVar);

function helloCatAsync() {
    setTimeout(function() {
        outerScopeVar = 'Nya';
    }, Math.random() * 2000);
}

Lưu ý: Tôi đang sử dụng setTimeoutvới một sự chậm trễ ngẫu nhiên như một chức năng không đồng bộ chung chung, ví dụ tương tự áp dụng cho Ajax, readFile, onloadvà bất kỳ dòng chảy không đồng bộ khác.

Ví dụ này rõ ràng gặp phải vấn đề tương tự như các ví dụ khác, đó là không đợi cho đến khi thực thi hàm không đồng bộ.

Hãy giải quyết nó bằng cách triển khai một hệ thống gọi lại của riêng chúng ta. Trước hết, chúng tôi loại bỏ cái xấu xí outerScopeVarđó hoàn toàn vô dụng trong trường hợp này. Sau đó, chúng tôi thêm một tham số chấp nhận một đối số hàm, gọi lại của chúng tôi. Khi hoạt động không đồng bộ kết thúc, chúng tôi gọi cuộc gọi lại này truyền kết quả. Việc thực hiện (vui lòng đọc các ý kiến ​​theo thứ tự):

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}

Đoạn mã của ví dụ trên:

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
console.log("1. function called...")
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    console.log("5. result is: ", result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    console.log("2. callback here is the function passed as argument above...")
    // 3. Start async operation:
    setTimeout(function() {
    console.log("3. start async operation...")
    console.log("4. finished async operation, calling the callback, passing the result...")
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}

Thông thường, trong các trường hợp sử dụng thực, API DOM và hầu hết các thư viện đã cung cấp chức năng gọi lại (cách helloCatAsynctriển khai trong ví dụ minh họa này). Bạn chỉ cần chuyển hàm gọi lại và hiểu rằng nó sẽ thực thi ngoài luồng đồng bộ và cấu trúc lại mã của bạn để phù hợp với điều đó.

Bạn cũng sẽ nhận thấy rằng do tính chất không đồng bộ, không thể để returnmột giá trị từ luồng không đồng bộ quay trở lại luồng đồng bộ nơi lệnh gọi lại được xác định, vì lệnh gọi lại không đồng bộ được thực thi lâu sau khi mã đồng bộ đã thực thi xong.

Thay vì nhập returnmột giá trị từ một lệnh gọi lại không đồng bộ, bạn sẽ phải sử dụng mẫu gọi lại, hoặc ... Lời hứa.

Lời hứa

Mặc dù có nhiều cách để ngăn chặn callback hell với vani JS, nhưng các hứa hẹn đang ngày càng phổ biến và hiện đang được tiêu chuẩn hóa trong ES6 (xem Promise - MDN ).

Promises (hay còn gọi là Futures) cung cấp cách đọc mã không đồng bộ tuyến tính hơn và do đó dễ chịu hơn, nhưng việc giải thích toàn bộ chức năng của chúng nằm ngoài phạm vi của câu hỏi này. Thay vào đó, tôi sẽ để lại những tài nguyên tuyệt vời này cho những người quan tâm:


Tài liệu đọc thêm về tính không đồng bộ của JavaScript


Lưu ý: Tôi đã đánh dấu câu trả lời này là Wiki Cộng đồng, do đó bất kỳ ai có ít nhất 100 danh tiếng đều có thể chỉnh sửa và cải thiện nó! Vui lòng cải thiện câu trả lời này hoặc gửi một câu trả lời hoàn toàn mới nếu bạn muốn.

Tôi muốn chuyển câu hỏi này thành một chủ đề chính tắc để trả lời các vấn đề không đồng bộ không liên quan đến Ajax (có Làm cách nào để trả lại phản hồi từ cuộc gọi không đồng bộ? Cho điều đó), do đó chủ đề này cần sự trợ giúp của bạn để trở nên tốt và hữu ích nhất có thể !

158
Matt 2014-05-29 23:09.

Câu trả lời của Fabrício là đúng; nhưng tôi muốn bổ sung câu trả lời của anh ấy bằng một cái gì đó ít kỹ thuật hơn, tập trung vào phép loại suy để giúp giải thích khái niệm không đồng bộ .


Phép tương tự ...

Hôm qua, công việc tôi đang làm yêu cầu một số thông tin từ một đồng nghiệp. Tôi gọi cho anh ta; đây là cách cuộc trò chuyện diễn ra:

Me : Hi Bob, tôi cần phải biết làm thế nào chúng ta foo 'd các thanh ' d tuần trước. Jim muốn báo cáo về nó và bạn là người duy nhất biết chi tiết về nó.

Bob : Chắc chắn rồi, nhưng tôi sẽ mất khoảng 30 phút?

Tôi : Thật tuyệt, Bob. Hãy trả lại cho tôi khi bạn có thông tin!

Đến lúc này, tôi cúp máy. Vì tôi cần thông tin từ Bob để hoàn thành báo cáo của mình, nên tôi rời báo cáo và đi uống cà phê, sau đó tôi nhận được một số email. 40 phút sau (Bob chậm), Bob gọi lại và cho tôi thông tin tôi cần. Tại thời điểm này, tôi tiếp tục công việc với báo cáo của mình, vì tôi đã có tất cả thông tin cần thiết.


Hãy tưởng tượng nếu cuộc trò chuyện diễn ra như thế này;

Me : Hi Bob, tôi cần phải biết làm thế nào chúng ta foo 'd các thanh ' d tuần trước. Jim muốn báo cáo về nó, và bạn là người duy nhất biết chi tiết về nó.

Bob : Chắc chắn rồi, nhưng tôi sẽ mất khoảng 30 phút?

Tôi : Thật tuyệt, Bob. Tôi sẽ đợi.

Và tôi ngồi đó và chờ đợi. Và đã đợi. Và đã đợi. Trong 40 phút. Không làm gì khác ngoài chờ đợi. Cuối cùng, Bob đã cung cấp cho tôi thông tin, chúng tôi gác máy và tôi đã hoàn thành báo cáo của mình. Nhưng tôi đã mất 40 phút năng suất.


Đây là hành vi không đồng bộ so với hành vi đồng bộ

Đây chính xác là những gì đang xảy ra trong tất cả các ví dụ trong câu hỏi của chúng tôi. Tải hình ảnh, tải tệp ra đĩa và yêu cầu trang qua AJAX đều là những hoạt động chậm chạp (trong bối cảnh máy tính hiện đại).

Thay vì chờ đợi các hoạt động chậm này hoàn thành, JavaScript cho phép bạn đăng ký một hàm gọi lại sẽ được thực thi khi hoạt động chậm đã hoàn thành. Tuy nhiên, trong khi chờ đợi, JavaScript sẽ tiếp tục thực thi mã khác. Thực tế là JavaScript thực thi mã khác trong khi đợi hoạt động chậm hoàn thành làm cho hành vi không đồng bộ . Nếu JavaScript đợi hoạt động hoàn tất trước khi thực thi bất kỳ mã nào khác, thì đây sẽ là hành vi đồng bộ .

var outerScopeVar;    
var img = document.createElement('img');

// Here we register the callback function.
img.onload = function() {
    // Code within this function will be executed once the image has loaded.
    outerScopeVar = this.width;
};

// But, while the image is loading, JavaScript continues executing, and
// processes the following lines of JavaScript.
img.src = 'lolcat.png';
alert(outerScopeVar);

Trong đoạn mã trên, chúng tôi yêu cầu JavaScript tải lolcat.png, đây là một hoạt động sloooow . Hàm gọi lại sẽ được thực thi sau khi hoạt động chậm này hoàn tất, nhưng trong thời gian chờ đợi, JavaScript sẽ tiếp tục xử lý các dòng mã tiếp theo; tức là alert(outerScopeVar).

Đây là lý do tại sao chúng tôi thấy cảnh báo hiển thị undefined; vì alert()nó được xử lý ngay lập tức, thay vì sau khi hình ảnh đã được tải.

Để sửa mã của chúng tôi, tất cả những gì chúng tôi phải làm là di chuyển alert(outerScopeVar)vào hàm gọi lại. Do đó, chúng ta không cần outerScopeVarbiến được khai báo như một biến toàn cục nữa.

var img = document.createElement('img');

img.onload = function() {
    var localScopeVar = this.width;
    alert(localScopeVar);
};

img.src = 'lolcat.png';

Bạn sẽ luôn thấy một lệnh gọi lại được chỉ định dưới dạng một hàm, vì đó là cách * duy nhất trong JavaScript để xác định một số mã, nhưng không thực thi nó cho đến sau này.

Do đó, trong tất cả các ví dụ của chúng tôi, function() { /* Do something */ }gọi lại là; để sửa chữa tất cả các ví dụ, tất cả những gì chúng ta phải làm là di chuyển mã cần phản hồi của hoạt động vào đó!

* Về mặt kỹ thuật, bạn có thể sử dụng eval()là tốt, nhưng eval()là ác cho mục đích này


Làm cách nào để giữ cho người gọi của tôi đợi?

Bạn hiện có thể có một số mã tương tự như thế này;

function getWidthOfImage(src) {
    var outerScopeVar;

    var img = document.createElement('img');
    img.onload = function() {
        outerScopeVar = this.width;
    };
    img.src = src;
    return outerScopeVar;
}

var width = getWidthOfImage('lolcat.png');
alert(width);

Tuy nhiên, bây giờ chúng ta biết rằng điều đó return outerScopeVarxảy ra ngay lập tức; trước khi onloadhàm gọi lại đã cập nhật biến. Điều này dẫn đến việc getWidthOfImage()quay trở lại undefinedundefinedđược cảnh báo.

Để khắc phục điều này, chúng ta cần cho phép hàm đang gọi getWidthOfImage()đăng ký một cuộc gọi lại, sau đó di chuyển cảnh báo về độ rộng nằm trong lệnh gọi lại đó;

function getWidthOfImage(src, cb) {     
    var img = document.createElement('img');
    img.onload = function() {
        cb(this.width);
    };
    img.src = src;
}

getWidthOfImage('lolcat.png', function (width) {
    alert(width);
});

... như trước đây, hãy lưu ý rằng chúng tôi đã có thể xóa các biến toàn cục (trong trường hợp này width).

75
JohnnyHK 2015-01-21 13:42.

Dưới đây là câu trả lời ngắn gọn hơn cho những người đang tìm kiếm tài liệu tham khảo nhanh cũng như một số ví dụ sử dụng hứa hẹn và async / await.

Bắt đầu với cách tiếp cận ngây thơ (không hoạt động) cho một hàm gọi một phương thức không đồng bộ (trong trường hợp này setTimeout) và trả về một thông báo:

function getMessage() {
  var outerScopeVar;
  setTimeout(function() {
    outerScopeVar = 'Hello asynchronous world!';
  }, 0);
  return outerScopeVar;
}
console.log(getMessage());

undefinedđược ghi lại trong trường hợp này vì getMessagetrả về trước khi setTimeoutgọi lại và cập nhật outerScopeVar.

Hai cách chính để giải quyết nó là sử dụng các lệnh gọi lạilời hứa :

Gọi lại

Thay đổi ở đây là getMessagechấp nhận một callbacktham số sẽ được gọi để cung cấp kết quả trở lại mã gọi khi có sẵn.

function getMessage(callback) {
  setTimeout(function() {
    callback('Hello asynchronous world!');
  }, 0);
}
getMessage(function(message) {
  console.log(message);
});

Lời hứa

Lời hứa cung cấp một giải pháp thay thế linh hoạt hơn lệnh gọi lại vì chúng có thể được kết hợp một cách tự nhiên để điều phối nhiều hoạt động không đồng bộ. Một Promises / A + thực hiện tiêu chuẩn được quy định tại natively Node.js (0.12+) và nhiều trình duyệt hiện nay, mà còn được thực hiện trong các thư viện như BluebirdQ .

function getMessage() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve('Hello asynchronous world!');
    }, 0);
  });
}

getMessage().then(function(message) {
  console.log(message);  
});

jQuery Trì hoãn

jQuery cung cấp chức năng tương tự như những lời hứa với Deferreds của nó.

function getMessage() {
  var deferred = $.Deferred();
  setTimeout(function() {
    deferred.resolve('Hello asynchronous world!');
  }, 0);
  return deferred.promise();
}

getMessage().done(function(message) {
  console.log(message);  
});

async / await

Nếu môi trường JavaScript của bạn bao gồm hỗ trợ cho asyncawait(như Node.js 7.6+), thì bạn có thể sử dụng đồng bộ các hứa hẹn trong các asynchàm:

function getMessage () {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve('Hello asynchronous world!');
        }, 0);
    });
}

async function main() {
    let message = await getMessage();
    console.log(message);
}

main();
58
Johannes Fahrenkrug 2015-12-09 06:48.

Để nói rõ ràng, cái cốc đại diện cho outerScopeVar.

Các hàm không đồng bộ giống như ...

14
Teja 2016-02-26 17:59.

Các câu trả lời khác là tuyệt vời và tôi chỉ muốn cung cấp một câu trả lời thẳng cho vấn đề này. Chỉ giới hạn các cuộc gọi không đồng bộ jQuery

Tất cả các lệnh gọi ajax (bao gồm cả $.gethoặc $.posthoặc $.ajax) là không đồng bộ.

Xem xét ví dụ của bạn

var outerScopeVar;  //line 1
$.post('loldog', function(response) {  //line 2
    outerScopeVar = response;
});
alert(outerScopeVar);  //line 3

Quá trình thực thi mã bắt đầu từ dòng 1, khai báo biến và kích hoạt và cuộc gọi không đồng bộ trên dòng 2, (tức là yêu cầu đăng) và nó tiếp tục thực hiện từ dòng 3, mà không cần đợi yêu cầu đăng hoàn thành việc thực thi.

Giả sử yêu cầu đăng bài mất 10 giây để hoàn thành, giá trị của outerScopeVarsẽ chỉ được đặt sau 10 giây đó.

Để thử,

var outerScopeVar; //line 1
$.post('loldog', function(response) {  //line 2, takes 10 seconds to complete
    outerScopeVar = response;
});
alert("Lets wait for some time here! Waiting is fun");  //line 3
alert(outerScopeVar);  //line 4

Bây giờ khi bạn thực hiện điều này, bạn sẽ nhận được một cảnh báo trên dòng 3. Bây giờ, hãy đợi một lúc cho đến khi bạn chắc chắn rằng yêu cầu bài đăng đã trả lại một số giá trị. Sau đó, khi bạn bấm OK, trên hộp cảnh báo, cảnh báo tiếp theo sẽ in ra giá trị mong đợi, vì bạn đã đợi nó.

Trong kịch bản cuộc sống thực, mã trở thành,

var outerScopeVar;
$.post('loldog', function(response) {
    outerScopeVar = response;
    alert(outerScopeVar);
});

Tất cả mã phụ thuộc vào các lệnh gọi không đồng bộ, được di chuyển bên trong khối không đồng bộ hoặc bằng cách chờ các lệnh gọi không đồng bộ.

11
Tom Sebastian 2015-10-27 20:35.

Trong tất cả các trường hợp outerScopeVarnày được sửa đổi hoặc gán một giá trị không đồng bộ hoặc xảy ra trong thời gian sau (chờ hoặc lắng nghe một số sự kiện xảy ra), mà quá trình thực thi hiện tại sẽ không chờ đợi . Vì vậy, tất cả các trường hợp này, luồng thực thi hiện tại dẫn đếnouterScopeVar = undefined

Hãy thảo luận về từng ví dụ (tôi đã đánh dấu phần được gọi là không đồng bộ hoặc bị trì hoãn đối với một số sự kiện xảy ra):

1.

Ở đây chúng ta đăng ký một eventlistner đó sẽ được thực hiện khi mà đặc biệt event.Here tải image.Then việc thực hiện liên tục với dòng tiếp theo img.src = 'lolcat.png';alert(outerScopeVar);khi đó sự kiện này có thể không xảy ra. tức là, img.onloadchờ đợi cho hình ảnh được giới thiệu tải không đồng bộ. Điều này sẽ xảy ra tất cả các ví dụ sau đây - sự kiện có thể khác.

2.

Ở đây, sự kiện thời gian chờ đóng vai trò, sẽ gọi trình xử lý sau thời gian được chỉ định. Đây rồi 0, nhưng nó vẫn đăng ký một sự kiện không đồng bộ, nó sẽ được thêm vào vị trí cuối cùng của quá trình Event Queuethực thi, điều này làm cho độ trễ được đảm bảo.

3.

Lần này gọi lại ajax.

4.

Node có thể được coi là vua của mã hóa không đồng bộ, ở đây hàm được đánh dấu được đăng ký như một trình xử lý gọi lại sẽ được thực thi sau khi đọc tệp được chỉ định.

5.

Lời hứa hiển nhiên (điều gì đó sẽ được thực hiện trong tương lai) là không đồng bộ. xem Sự khác biệt giữa Trì hoãn, Hứa hẹn và Tương lai trong JavaScript là gì?

https://www.quora.com/Whats-the-difference-between-a-promise-and-a-callback-in-Javascript

Related questions

MORE COOL STUFF

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

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.

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

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ì?

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

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.

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

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.

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

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!

8 công dụng tuyệt vời của Baking Soda và Giấm

8 công dụng tuyệt vời của Baking Soda và Giấm

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.

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

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?

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

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.

Một thương hiệu kế thừa khác có được cuộc sống mới khi những người chủ mới của Black Opal có được Hội chợ thời trang

Một thương hiệu kế thừa khác có được cuộc sống mới khi những người chủ mới của Black Opal có được Hội chợ thời trang

Desiree Rogers, trái, và Cheryl Mayberry McKissack Chuyển sang, Fenty Beauty và Pat McGrath, có một đế chế làm đẹp mới do phụ nữ làm chủ đang trỗi dậy. Sau thương vụ mua lại mỹ phẩm Black Opal vào tháng 9, đội ngũ quyền lực của Giám đốc điều hành công ty Desiree Rogers và Chủ tịch Cheryl Mayberry McKissack đã thông báo mua lại thương hiệu làm đẹp tiên phong Fashion Fair từ người sáng lập Johnson Publishing Company (JPC).

Ngoài việc trở nên vô nghĩa, các bên bộc lộ giới tính giờ đây đã trở nên chết người

Ngoài việc trở nên vô nghĩa, các bên bộc lộ giới tính giờ đây đã trở nên chết người

Đối với những người có quá nhiều thời gian, tiệc tiết lộ giới tính là một cách thú vị để không cần áp đặt những định kiến ​​hạn chế lên thai nhi trước một đối tượng bạn bè giả vờ quan tâm một cách lịch sự. Tuy nhiên, việc chỉ dựa vào những chiếc bánh nướng có màu nhân tạo để biểu thị một tiếng hoo-ha hoặc một đứa trẻ đi tè đã trở nên xa xỉ trong các bậc cha mẹ trên Instagram.

Kirstjen Nielsen đang cố gắng đổi mới bản thân với tư cách là một người phụ nữ 'nói ra sự thật cho sức mạnh'

Kirstjen Nielsen đang cố gắng đổi mới bản thân với tư cách là một người phụ nữ 'nói ra sự thật cho sức mạnh'

Hôm thứ Tư, cựu Bộ trưởng An ninh Nội địa Kirstjen Nielsen vì một lý do nào đó đã được đưa ra một diễn đàn để phát biểu tại Hội nghị thượng đỉnh Những người phụ nữ quyền lực nhất của Fortune. Và có thể đoán trước được, người phụ nữ giám sát các nỗ lực (đang diễn ra) của chính quyền Trump nhằm chia cắt các gia đình ở biên giới đã sử dụng thời gian của mình như một cơ hội để tự bảo vệ mình và tự nhận mình là người — và hãy hít thở sâu ở đây — “đã nói sự thật với quyền lực.

Toyota Racing Development sẽ cho ra mắt Supra 3000GT Concept, Massive Wing vào tháng tới

Toyota Racing Development sẽ cho ra mắt Supra 3000GT Concept, Massive Wing vào tháng tới

Vì thế hệ mới nhất của chiếc xe điều chỉnh được yêu thích trên thế giới hiện đã có mặt tại đây, nên chỉ có điều kiện là Toyota Racing Development sẽ đưa phiên bản Supra thế hệ thứ năm sửa đổi của riêng mình đến SEMA vào tháng tới. Toyota đã cho chúng tôi một gợi ý về những gì sẽ xảy ra trong tuần này: một chiếc Concept GR Supra 3000GT hiện đại.

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

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

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

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ì!

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

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

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Vụ kiện, nêu tên một số học khu, lập luận rằng dự luật "Không nói đồng tính" được ban hành gần đây của Florida "có hiệu quả im lặng và xóa bỏ học sinh và gia đình LGBTQ +"

Đường băng hạ cánh

Đường băng hạ cánh

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.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

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.

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

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.

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Tôi ghét từ "tàu đắm". Mọi người cảm thấy thoải mái trong la bàn đạo đức của riêng mình, và khi làm như vậy, họ thấy mình vượt qua sự phán xét.

Language