Краткий ответ: ваш метод foo()
возвращается немедленно, а вызов $ajax()
выполняется асинхронно после возврата функции . Проблема заключается в том, как и где сохранить результаты, полученные при вызове async, после его возврата.
В этом потоке было задано несколько решений. Возможно, самый простой способ - передать объект методу foo()
и сохранить результаты в члене этого объекта после завершения асинхронного вызова.
function foo(result) {
$.ajax({
url: '...',
success: function(response) {
result.response = response; // Store the async result
}
});
}
var result = { response: null }; // Object to hold the async result
foo(result); // Returns before the async completes
Обратите внимание, что вызов foo()
] все равно не вернут ничего полезного. Однако результат асинхронного вызова теперь будет сохранен в result.response
.
Некоторым людям не нравится этот подход из-за «неуместного» использования обработки ошибок, но я думаю, что это считается приемлемым в VBA ... Альтернативный подход заключается в том, чтобы зацикливать все листы, пока вы не найдете совпадение.
Function SheetExists(shtName As String, Optional wb As Workbook) As Boolean
Dim sht As Worksheet
If wb Is Nothing Then Set wb = ThisWorkbook
On Error Resume Next
Set sht = wb.Sheets(shtName)
On Error GoTo 0
SheetExists = Not sht Is Nothing
End Function
Я написал это:
Function sheetExist(sSheet As String) As Boolean
On Error Resume Next
sheetExist = (ActiveWorkbook.Sheets(sSheet).Index > 0)
End Function
wsExists
( без зависит от обработки ошибок!) [/ g6] Вот короткий & amp; простую функцию, которая не полагается на обработку ошибок, чтобы определить, существует ли рабочий лист ( и ], [3], [3] hr>
В следующем примере добавляется новый лист с именем myNewSheet
, если он еще не существует:
If Not wsExists("myNewSheet") Then Sheets.Add.Name = "myNewSheet"
For Each
... Next
Statement (VBA) Exit
Statement (VBA) На самом деле у меня был простой способ проверить, существует ли лист, а затем выполнить некоторую инструкцию:
В моем случае я хотел удалить лист, а затем воссоздал тот же лист с тем же именем, но код был прерван, если программа не смогла удалить лист, поскольку он уже был удален
Sub Foo ()
Application.DisplayAlerts = False
On Error GoTo instructions
Sheets("NAME OF THE SHEET").Delete
instructions:
Sheets.Add After:=Sheets(Sheets.Count)
ActiveSheet.Name = "NAME OF THE SHEET"
End Sub
Измените «данные» на любое имя листа, которое вы тестируете для ...
On Error Resume Next
Set DataSheet = Sheets("Data")
If DataSheet Is Nothing Then
Sheets.Add(after:=ActiveSheet).Name = "Data"
''or whatever alternate code you want to execute''
End If
On Error GoTo 0
Для этого вам не нужна обработка ошибок. Все, что вам нужно сделать, это перебрать все листы и проверить, существует ли указанное имя:
For i = 1 To Worksheets.Count
If Worksheets(i).Name = "MySheet" Then
exists = True
End If
Next i
If Not exists Then
Worksheets.Add.Name = "MySheet"
End If
Я придумал простой способ сделать это, но я не создал для него новую подсистему. Вместо этого я просто «проверил чек» в суб, над которым я работал. Предполагая, что имя листа, которое мы ищем, является «Sheet_Exist», и мы просто хотим его активировать, если он найден:
Dim SheetCounter As Integer
SheetCounter = 1
Do Until Sheets(SheetCounter).Name = "Sheet_Exist" Or SheetCounter = Sheets.Count + 1
SheetCounter = SheetCounter +1
Loop
If SheetCounter < Sheets.Count + 1 Then
Sheets("Sheet_Exist").Activate
Else
MsgBox("Worksheet ""Sheet_Exist"" was NOT found")
End If
Я также добавил всплывающее окно, когда лист не существует.
Положите тест в функцию, и вы сможете его повторно использовать, и у вас будет более удобная читаемость кода.
НЕ используйте «On Error Resume Next», так как это может конфликтовать с другой частью вашего код.
Sub DoesTheSheetExists()
If SheetExist("SheetName") Then
Debug.Print "The Sheet Exists"
Else
Debug.Print "The Sheet Does NOT Exists"
End If
End Sub
Function SheetExist(strSheetName As String) As Boolean
Dim i As Integer
For i = 1 To Worksheets.Count
If Worksheets(i).Name = strSheetName Then
SheetExist = True
Exit Function
End If
Next i
End Function
Поскольку проверка членов коллекции является общей проблемой, вот абстрагированная версия ответа Тима:
Function Contains(objCollection As Object, strName as String) As Boolean Dim o as Object On Error Resume Next set o = objCollection(strName) Contains = (Err.Number = 0) Err.Clear End Function
Эта функция может использоваться с любой коллекцией, подобной объекту (Shapes
, Range
, Names
, Workbooks
и т. д.).
Чтобы проверить наличие листа, используйте If Contains(Sheets, "SheetName") ...
Public Function WorkSheetExists(ByVal strName As String) As Boolean
On Error Resume Next
WorkSheetExists = Not Worksheets(strName) Is Nothing
End Function
sub test_sheet()
If Not WorkSheetExists("SheetName") Then
MsgBox "Not available"
Else MsgBox "Available"
End If
End Sub
Если вас интересуют только рабочие листы, вы можете использовать простой вызов Evaluate:
Function WorksheetExists(sName As String) As Boolean
WorksheetExists = Evaluate("ISREF('" & sName & "'!A1)")
End Function
Почему бы просто не использовать небольшой цикл, чтобы определить, существует ли именованный лист? Скажите, искали ли вы рабочую таблицу с именем «Sheet1» в текущей книге.
Dim wb as Workbook
Dim ws as Worksheet
Set wb = ActiveWorkbook
For Each ws in wb.Worksheets
if ws.Name = "Sheet1" then
'Do something here
End if
Next
Я сделал другое: удалите лист только в том случае, если он существует - не получить ошибку, если это не так:
Excel.DisplayAlerts = False
Dim WS
For Each WS In Excel.Worksheets
If WS.name = "Sheet2" Then
Excel.sheets("Sheet2").Delete
Exit For
End If
Next
Excel.DisplayAlerts = True
For Each Sheet In Worksheets
If UCase(Sheet.Name) = "TEMP" Then
'Your Code when the match is True
Application.DisplayAlerts = False
Sheet.Delete
Application.DisplayAlerts = True
'-----------------------------------
End If
Next Sheet
Мое решение очень похоже на Tims, но также работает в случае листов без листа - диаграммы
Public Function SheetExists(strSheetName As String, Optional wbWorkbook As Workbook) As Boolean
If wbWorkbook Is Nothing Then Set wbWorkbook = ActiveWorkbook 'or ThisWorkbook - whichever appropriate
Dim obj As Object
On Error GoTo HandleError
Set obj = wbWorkbook.Sheets(strSheetName)
SheetExists = True
Exit Function
HandleError:
SheetExists = False
End Function
.
В случае, если кто-то хочет избежать VBA и проверить, существует ли таблица только внутри формулы ячейки, возможно использование функций ISREF
и INDIRECT
:
=ISREF(INDIRECT("SheetName!A1"))
Это вернет TRUE
, если книга содержит лист, названный SheetName
и FALSE
в противном случае.
Если вы поклонник WorksheetFunction.
или работаете в неанглийской стране с неанглийским Excel, это хорошее решение, которое работает:
WorksheetFunction.IsErr(Evaluate("'" & wsName & "'!A1"))
Или в функции например:
Function WorksheetExists(sName As String) As Boolean
WorksheetExists = Not WorksheetFunction.IsErr(Evaluate("'" & sName & "'!A1"))
End Function
Много лет спустя, но мне просто нужно было это сделать, и мне не понравилось, что какое-либо из решений было опубликовано ... Итак, я сделал все, благодаря магии (жестом в форме радуги SpongeBob) «Evaluate ()» !
Evaluate("IsError(" & vSheetName & "!1:1)")
Возвращает TRUE, если лист НЕ существует; FALSE, если лист существует. Вы можете заменить любой диапазон, который вам нравится, на «1: 1», но я советую не использовать одну ячейку, потому что если она содержит ошибку (например, # N / A), она вернет True.