Причина в том, что Обещания асинхронны:
logOut("start of file");
new Promise(function(accept){
accept();
}).then(function(){
logOut("inside promise");
});
function makePromise(name) {
new Promise(function(accept){
accept();
}).then(function(){
logOut("inside promise inside makePromise " + name);
});
};
logOut("value returned from makePromise: " + makePromise("one"));
try {
// just to prove this
makePromise("two").then(function(accept){
accept();
}).then(function(){
logOut("after makePromise");
});
} catch(err) {
logOut("Failed to `.then` the return value from makePromise because:\n" + err.message);
}
logOut("end of file");
var outputList;
function logOut(str){
outputList = outputList || document.getElementById("output");
outputList.insertAdjacentHTML("beforeend", "" + str + "
");}
<ol id="output"></ol>
Как видно выше, вся программа не делает паузу для оператора .then
.почему они называются Обещаниями: потому что остальная часть кода продолжается, пока Обещание ожидает разрешения. Кроме того, как видно выше, может быть значение, возвращаемое функцией, только если функция явно возвращает значение через then
ключевое слово. Функции JavaScript не возвращают автоматически значение последнего выполненного оператора.
Для получения дополнительной информации об обещаниях см. мой веб-сайт .
В демонстрационном примере нижеЯ попытался исправить фрагменты файлов, которые вы ударили по этому вопросу, а затем приступил к объединению их в быструю однофайловую систему, которую я набрал
(function(){"use strict";
// NOTE: This setup code makes no attempt to accurately replicate the
// NodeJS api. This setup code only tries to concisely mimics
// the NodeJS API solely for the purposes of preserving your code
// in its present NodeJS form.
var modules = {}, require = function(fileName){return modules[fileName]};
for (var i=0; i < arguments.length; i=i+1|0)
arguments[i]({exports: modules[arguments[i].name] = {}}, require);
})(function https(module, require){"use strict";
////////////// https.js //////////////
module.exports.request = function(options, withWrapper) {
var p, when = {}, wrapper = {on: function(name, handle){
when[name] = handle;
}, end: setTimeout.bind(null, function(){
if (p === "/api/getOne/world") when.data("HTTP bar in one 1");
else if (p === "/api/getTwo/foo") when.data("HTTP foo in two 2");
else {console.error("Not stored path: '" + p + "'");
return setTimeout(when.error);}
setTimeout(when.end); // setTimeout used for asynchrony
}, 10 + Math.random()*30)}; // simulate random http delay
setTimeout(withWrapper, 0, wrapper); // almost setImmediate
return p = options.path, options = null, wrapper;
};
/******* IGNORE ALL CODE ABOVE THIS LINE *******/
}, function myModule(module, require) {"use strict";
////////////// myModule.js //////////////
const HttpsModule = require('https');
module.exports.getApiOne = function(value) {
var params = {path: '/api/getOne/' + value};
// There is no reason for `.then(response => response);`!
// It does absolutely nothing.
return getApi(params); // .then(response => response);
};
module.exports.getApiTwo = function(value) {
var params = {path: '/api/getTwo/' + value};
return getApi(params); // .then(response => response);
};
function getApi(params) {
return new Promise(function(resolve, reject) {
var req = HttpsModule.request(params, function(res) {
var body = [];
res.on('data', function(chunk) {
body.push(chunk);
});
res.on('end', function() {
try {
body = body.join("");//Buffer.concat(body).toString();
} catch (e) {
reject(e);
}
resolve(body);
});
});
req.on('error', function(err) {
reject(err);
});
req.end();
});
}
}, function main(module, require) {"use strict";
////////////// top JS script //////////////
const MyStatusModule = require('myModule');
const isPromise = isPrototypeOf.bind(Promise.prototype)
var someObject = {};
function someFunction(inputObject) {
// initialize object
// NOTE: Javascript IS case-sensitive, so `.Id` !== `.id`
if (!someObject.hasOwnProperty(inputObject.id)) {
someObject[inputObject.id] = {};
someObject[inputObject.id].contact = {};
}
// get object
var objectForThis = someObject[inputObject.id];
switch (inputObject.someValue) {
case 'test':
//... some code
return objectForThis.stage = 'test';
break;
case 'hello':
return MyStatusModule.getApiOne('world').then(function (response) {
// console.log(response);
return objectForThis.stage = 'zero'
});
break;
default:
return someOtherFunction(objectForThis.stage).then(function (response) {
return objectForThis.stage = response;
});
break;
}
}
function someOtherFunction(stage) {
var newStage;
// If you return nothing, then you would be calling `.then` on
// on `undefined` (`undefined` is the default return value).
// This would throw an error.
return new Promise(function(resolve, reject) {
switch (stage) {
case 'zero':
// some code
newStage = 'one';
resolve(newStage); // you must call `resolve`
case 'one':
return MyStatusModule.getApiTwo('foo').then(function (response) {
// console.log(response);
newStage = 'two';
/********************************************
I assume, the problem lies here, it's
'resolving' (below) before this sets the new
value for 'newStage'
********************************************/
resolve(newStage); // you must call `resolve`
});
break;
default:
// do nothing
resolve(newStage); // you must call `resolve`
break;
}
});
}
// tests:
function logPromise(){
var a=arguments, input = a[a.length-1|0];
if (isPromise(input)) {
for (var c=[null], i=0; i<(a.length-1|0); i=i+1|0) c.push(a[i]);
return input.then(logPromise.bind.apply(logPromise, c));
} else console.log.apply(console, arguments);
}
logPromise("test->test: ", someFunction({id: 1, someValue: 'test'})); // sets 'stage' to 'test'
logPromise("hello->zero: ", someFunction({id: 1, someValue: 'hello'})) // sets 'stage' to 'zero'
.finally(function(){ // `.finally` is like `.then` without arguments
// This `.finally` waits until the HTTP request is done
logPromise("foo->one: ", someFunction({id: 1, someValue: 'foo'})) // sets 'stage' to 'one'
.finally(function(){
debugger;
logPromise("bar->two: ", someFunction({id: 1, someValue: 'bar'})); // NOT setting 'stage' to 'two'
});
});
});
Если это уже не очевидно, не копируйте приведенный выше фрагмент в свой код.Это нарушит ваш код, потому что приведенный выше фрагмент содержит фиктивные модули Node, предназначенные для получения заданных результатов.Вместо этого скопируйте каждый отдельный файл (каждый обернутый в функцию) из приведенного выше фрагмента в соответствующий файл вашего кода, если вам необходимо скопировать.Кроме того, при копировании имейте в виду, что не копируйте пустышки над ярким индикатором IGNORE ALL CODE ABOVE THIS LINE
.Также не забывайте проверять строго.Я гораздо больше знаком с браузерным JavaScript, чем с Node JavaScript, поэтому возможно (хотя и маловероятно), что я мог внести потенциальный источник ошибок.
someObject[inputObject.id] = objectForThis;
не требуется
Я может дать вам очень краткий быстрый ответ на этот вопрос.Тем не менее, я чувствую, что «быстрый» ответ не будет справедливым, потому что этот конкретный вопрос требует гораздо большей глубины понимания, чтобы иметь возможность придумать объяснение, чем просто прочитать объяснение другого человека.Кроме того, это очень важная концепция в Javascript.Таким образом, очень важно иметь возможность придумать объяснение самостоятельно, чтобы вы не столкнулись с той же проблемой снова через 5 минут.Таким образом, я написал приведенный ниже учебник, который поможет вам найти ответ, чтобы вы могли быть уверены, что у вас есть полное понимание.
В Javascript есть такие выражения, как 7 - 4
, что дает 3
.Каждое выражение возвращает значение, которое может использоваться другими выражениями.3 * (4 + 1)
сначала оценивает 4 + 1
в 3 * 5
, затем это дает 15
.Выражения назначения (=
, +=
, -=
, *=
, /=
, %=
, **=
, &=
, |=
и ^=
) изменяют только левую рукупеременная.Любая правая переменная остается неизменной и содержит одно и то же значение:
var p = {};
var ptr = p;
// Checkpoint A:
console.log('Checkpoint A: p === ptr is now ' + (p === ptr));
ptr = null;
// Checkpoint B:
console.log('Checkpoint B: p === ptr is now ' + (p === ptr));
Давайте рассмотрим, как p
и ptr
выглядят на контрольной точке A.

As seen in the above diagram, both p
and ptr
are kept separate even though they both point to the same object. Thus, at Checkpoint B, changing ptr
to a different value does not change p
to a different value. At Checkpoint B, variable p
has remained unchanged while ptr
is now null
.
At Checkpoint A, keep in mind that (although p
and ptr
are distinct variables with different memory addresses) p
and ptr
both point to the same object because the location in memory they point to is the same index number. Thus, if we changed this object at checkpoint A, then reading/writing the properties of p
would be the same as reading/writing the properties of ptr
because you are changing the data being pointed to, not which variable is pointing to what data.
function visualize(inputObject) {
// displays an object as a human-readable JSON string
return JSON.stringify(inputObject);
}
var p = {};
p.hello = "world";
// Checkpoint 0:
console.log('Checkpoint 0: p is ' + visualize(p));
var ptr = p;
ptr.foo = "bar";
// Checkpoint A:
console.log('Checkpoint A: p is ' + visualize(p) + ' while ptr is ' + visualize(ptr));
ptr = null;
// Checkpoint B:
console.log('Checkpoint B: p is ' + visualize(p) + ' while ptr is ' + visualize(ptr));
p.foo = p.hello;
// Checkpoint C:
console.log('Checkpoint C: p is ' + visualize(p) + ' while ptr is ' + visualize(ptr));
Как видно на контрольной точке A выше, изменение p
аналогично изменению ptr
.Как насчет того, когда мы переназначаем объект?Старый объект, который больше не указывается, очищается автоматическим сборщиком мусора.
function visualize(inputObject) {
// displays an object as a human-readable JSON string
return JSON.stringify(inputObject);
}
var first = {one: "is first"};
first = {uno: "es el primero"};
var second = {two: "is second"};
second = first;
console.log("second is " + JSON.stringify(second));
Аргументы функции в этом отношении такие же, как и у переменных.
var obj = {};
setVariable(obj);
obj.key = "value";
console.log("obj is " + JSON.stringify(obj));
function setVariable(inputVariable){
inputVariable.setValue = "set variable value";
inputVariable = null;
}
То же, что и:
var obj = {};
/*function setVariable(*/ var inputVariable = obj; /*){*/
inputVariable.setValue = "set variable value";
inputVariable = null;
/*}*/
obj.key = "value";
console.log("obj is " + JSON.stringify(obj));
Объекты также ничем не отличаются:
function visualize(inputObject) {
// displays an object as a human-readable JSON string
return JSON.stringify(inputObject);
}
var variables = {};
var aliasVars = variables;
// Now, `variables` points to the same object as `aliasVars`
variables.p = {};
aliasVars.p.hello = "world";
// Checkpoint 0:
console.log('Checkpoint 0: variables are ' + visualize(variables));
console.log('Checkpoint 0: aliasVars are ' + visualize(aliasVars));
variables.ptr = aliasVars.p;
aliasVars.ptr.foo = "bar";
// Checkpoint A:
console.log('Checkpoint A: variables are ' + visualize(variables));
console.log('Checkpoint A: aliasVars are ' + visualize(aliasVars));
variables.ptr = null;
// Checkpoint B:
console.log('Checkpoint B: variables are ' + visualize(variables));
console.log('Checkpoint B: aliasVars are ' + visualize(aliasVars));
aliasVars.p.foo = variables.p.hello;
// Checkpoint C:
console.log('Checkpoint C: variables are ' + visualize(variables));
console.log('Checkpoint C: aliasVars are ' + visualize(aliasVars));
Далее идет обозначение объекта, чтобы убедиться, что мы находимся на той же странице.
var obj = {};
obj.one = 1;
obj.two = 2;
console.log( "obj is " + JSON.stringify(obj) );
совпадает с
var obj = {one: 1, two: 2};
console.log( "obj is " + JSON.stringify(obj) );
совпадает с
console.log( "obj is " + JSON.stringify({one: 1, two: 2}) );
совпадает с
console.log( "obj is {\"one\":1,\"two\":2}" );
hasOwnProperty
позволяет нам определить, есть ли у объекта свойство.
var obj = {};
// Checkpoint A:
console.log("Checkpoint A: obj.hasOwnProperty(\"hello\") is " + obj.hasOwnProperty("hello"));
console.log("Checkpoint A: obj[\"hello\"] is " + obj["hello"]);
obj.hello = "world"; // now set the variable
// Checkpoint B:
console.log("Checkpoint B: obj.hasOwnProperty(\"hello\") is " + obj.hasOwnProperty("hello"));
console.log("Checkpoint B: obj[\"hello\"] is " + obj["hello"]);
obj.hello = undefined;
// Checkpoint C:
console.log("Checkpoint C: obj.hasOwnProperty(\"hello\") is " + obj.hasOwnProperty("hello"));
console.log("Checkpoint C: obj[\"hello\"] is " + obj["hello"]);
delete obj.hello;
// Checkpoint D:
console.log("Checkpoint D: obj.hasOwnProperty(\"hello\") is " + obj.hasOwnProperty("hello"));
console.log("Checkpoint D: obj[\"hello\"] is " + obj["hello"]);
Прототипы в javascript имеют решающее значение для понимания hasOwnProperty
и работают следующим образом: когда свойство не найдено в объекте, объект __proto__ проверяется для объекта.Когда у объекта __proto__ нет свойства, для объекта проверяется __proto __proto__ объекта.Только после того, как объект без __proto__ достигнут, браузер полагает, что искомое свойство не существует.__Proto__ визуализируется ниже.
var obj = {};
console.log('A: obj.hasOwnProperty("foo") is ' + obj.hasOwnProperty("foo"));
console.log('A: obj.foo is ' + obj.foo);
obj.__proto__ = {
foo: 'value first'
};
console.log('B: obj.hasOwnProperty("foo") is ' + obj.hasOwnProperty("foo"));
console.log('B: obj.foo is ' + obj.foo);
obj.foo = 'value second';
console.log('C: obj.hasOwnProperty("foo") is ' + obj.hasOwnProperty("foo"));
console.log('C: obj.foo is ' + obj.foo);
delete obj.foo;
console.log('D: obj.hasOwnProperty("foo") is ' + obj.hasOwnProperty("foo"));
console.log('D: obj.foo is ' + obj.foo);
delete obj.__proto__.foo;
console.log('E: obj.hasOwnProperty("foo") is ' + obj.hasOwnProperty("foo"));
console.log('E: obj.foo is ' + obj.foo);
Фактически, мы можем даже сохранить ссылку на __proto__ и поделиться этой ссылкой между объектами.
var dog = {noise: "barks"};
var cat = {noise: "meow"};
var mammal = {animal: true};
dog.__proto__ = mammal;
cat.__proto__ = mammal;
console.log("dog.noise is " + dog.noise);
console.log("dog.animal is " + dog.animal);
dog.wagsTail = true;
cat.clawsSofa = true;
mammal.domesticated = true;
console.log("dog.wagsTail is " + dog.wagsTail);
console.log("dog.clawsSofa is " + dog.clawsSofa);
console.log("dog.domesticated is " + dog.domesticated);
console.log("cat.wagsTail is " + cat.wagsTail);
console.log("cat.clawsSofa is " + cat.clawsSofa);
console.log("cat.domesticated is " + cat.domesticated);
Однако приведенный выше синтаксис ужасно плохо работает, потому что неправильно изменять __proto__ после создания объекта.Таким образом, решение состоит в том, чтобы установить __proto__ вместе с созданием объекта.Это называется конструктором.
function Mammal(){}
// Notice how Mammal is a function, so you must do Mammal.prototype
Mammal.prototype.animal = true;
var dog = new Mammal();
// Notice how dog is an instance object of Mammal, so do NOT do dog.prototype
dog.noise = "bark";
var cat = new Mammal();
cat.noise = "meow";
console.log("dog.__proto__ is Mammal is " + (dog.__proto__===Mammal));
console.log("cat.__proto__ is Mammal is " + (cat.__proto__===Mammal));
console.log("dog.__proto__ is Mammal.prototype is " + (dog.__proto__===Mammal.prototype));
console.log("cat.__proto__ is Mammal.prototype is " + (cat.__proto__===Mammal.prototype));
console.log("dog.noise is " + dog.noise);
console.log("dog.animal is " + dog.animal);
dog.wagsTail = true;
cat.clawsSofa = true;
Mammal.prototype.domesticated = true;
console.log("dog.wagsTail is " + dog.wagsTail);
console.log("dog.clawsSofa is " + dog.clawsSofa);
console.log("dog.domesticated is " + dog.domesticated);
console.log("cat.wagsTail is " + cat.wagsTail);
console.log("cat.clawsSofa is " + cat.clawsSofa);
console.log("cat.domesticated is " + cat.domesticated);
Далее, объект this
в Javascript не является ссылкой на экземпляр, как в Java.Скорее, this
в Javascript ссылается на object
в выражении object.property()
, когда функции вызываются таким образом.Когда функции не вызываются таким образом, объект this
ссылается на undefined
в строгом режиме или window
в свободном режиме.
"use strict"; // "use strict"; at the VERY top of the file ensures strict mode
function logThis(title){
console.log(title + "`this === undefined` as " + (this === undefined));
if (this !== undefined) console.log(title + "`this.example_random_name` as " + this.example_random_name);
}
logThis.example_random_name = "log this raw function";
logThis("logThis() has ");
var wrapper = {logThis: logThis, example_random_name: "wrapper around logThis"};
wrapper.logThis("wrapper.logThis has ");
var outer = {wrapper: wrapper, example_random_name: "outer wrap arounde"};
outer.wrapper.logThis("outer.wrapper.logThis has ");
Мы можем наконец взять все эти знания и экстраполировать их на реальный пример.
var someObject = {};
function someFunction(inputObject) {
if (!someObject.hasOwnProperty(inputObject.id)) {
someObject[inputObject.id] = {};
someObject[inputObject.id].contact = {};
}
// get object
var objectForThis = someObject[inputObject.id];
objectForThis.stage = inputObject.stage;
}
var setTo = {};
setTo.id = 1;
setTo.stage = "first stage";
someFunction(setTo);
console.log("someObject is " + JSON.stringify(someObject));
Во-первых, давайте встроим функцию и setTo
var someObject = {};
var setTo = {id: 1, stage: "first stage"};
/*function someFunction(*/ var inputObject = setTo; /*) {*/
if (!someObject.hasOwnProperty(inputObject.id)) {
someObject[inputObject.id] = {};
someObject[inputObject.id].contact = {};
}
// get object
var objectForThis = someObject[inputObject.id];
objectForThis.stage = inputObject.stage;
/*}*/
console.log("someObject is " + JSON.stringify(someObject));
Далее, давайте вставим объект setTo
.
var someObject = {};
var setTo = {id: 1, stage: "first stage"};
if (!someObject.hasOwnProperty(setTo.id)) {
someObject[setTo.id] = {};
someObject[setTo.id].contact = {};
}
// get object
var objectForThis = someObject[setTo.id];
objectForThis.stage = setTo.stage;
console.log("someObject is " + JSON.stringify(someObject));
Затем:
var someObject = {};
if (!someObject.hasOwnProperty(1)) {
someObject[1] = {};
someObject[1].contact = {};
}
// get object
var objectForThis = someObject[1];
objectForThis.stage = "first stage";
console.log("someObject is " + JSON.stringify(someObject));
Чтобы наглядно продемонстрировать указатели:
var someObject = {};
if (!someObject.hasOwnProperty(1)) {
var createdObject = {};
someObject[1] = createdObject;
someObject[1].contact = {};
}
// get object
var objectForThis = someObject[1];
console.log("createdObject === objectForThis is " + (createdObject === objectForThis));
objectForThis.stage = "first stage";
console.log("someObject is " + JSON.stringify(someObject));
Пожалуйста, скажите мне, если у вас есть какие-либо дополнительные вопросы.
Если вы только посмотрите на это, то, пожалуйста, не забудьте прочитать статью полностьювыше.Я обещаю вам, что моя статья выше короче и пытается углубиться в Javascript, чем любая другая статья, которую вы можете найти в Интернете.